home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_guid / style-t.hlp < prev   
Text File  |  1996-01-30  |  553KB  |  16,229 lines

  1.  
  2.  
  3. Ada Quality and Style:
  4. Guidelines for Professional Programmers
  5.  
  6. SPC-91061-CMC
  7.  
  8. VERSION 02.01.01
  9.  
  10. December 1992
  11.  
  12.  
  13.  
  14.  
  15. Ada Quality and Style:
  16. Guidelines for Professional Programmers
  17.  
  18. SPC-91061-CMC
  19.  
  20. VERSION 02.01.01
  21.  
  22. December 1992
  23.  
  24.  
  25.  
  26. SOFTWARE PRODUCTIVITY CONSORTIUM, INC.
  27. SPC Building
  28. 2214 Rock Hill Road
  29. Herndon, Virginia 22070
  30.  
  31.  
  32. Copyright 1989, 1991,1992 Software Productivity Consortium, Inc., Herndon,
  33. Virginia. Permission to use, copy, modify and distribute this documentation
  34. for any purpose and without fee is hereby granted, provided that the above
  35. copyright notice appears in all copies and that both this copyright notice and
  36. this permission notice appear in supporting documentation, and that the name
  37. Software Productivity Consortium not be used in advertising or publicity
  38. pertaining to distribution of the guidelines without the specific, written
  39. prior permission of the Consortium. Software Productivity Consortium, Inc.
  40. makes no representations about the suitability of the guidelines described
  41. herein for any purpose and they are provided "as is" without express or
  42. implied warranty.
  43.  
  44.  
  45. -----
  46. Ada-ASSURED is a trademark of GrammaTech, Inc.
  47.  
  48. IBM is a registered trademark of International Business Machines Corporation.
  49.  
  50. VAX is a registered trademark of Digital Equipment Corporation.
  51.  
  52.  
  53. PREFACE
  54.  
  55. This version of Ada Quality and Style: Guidelines for Professional Programmers
  56. was updated under contract to the Department of Defense (DoD) Ada Joint
  57. Program Office (AJPO).  Considerable effort was placed on improving the
  58. coverage of portability and reusability issues, so the majority of changes can
  59. be found in those chapters.  A new chapter has been included to address
  60. performance issues.
  61.  
  62. The most visible change, however, involves the capitalization issue.  The 
  63. guideline has not changed, but the instantiation now recommends mixed-case 
  64. identifiers with upper-case abbreviations and lower-case reserved words.  
  65. Several informal surveys and the general consensus of the reviewers showed 
  66. strong support for this change.
  67.  
  68. The Complete Examples chapter includes two new examples which highlight 
  69. portability and the use of tasking.  Each of the examples in this chapter are 
  70. intended to be compilable and executable.
  71.  
  72. The Consortium invites comments on this guidebook to continue enhancing its
  73. quality and usefulness. We will consider suggestions for current guidelines
  74. and areas for future expansion. Examples that highlight particular points are
  75. most helpful.
  76.  
  77. Please direct comments to:
  78.  
  79. Technology Transfer Division - AQS
  80. Software Productivity Consortium
  81. SPC Building
  82. 2214 Rock Hill Road
  83. Herndon, Virginia 22070#4005
  84. (703) 742-7211
  85.  
  86. DoD activities and Defense contractors can obtain copies of this document 
  87. through the Defense Technical Information Center:
  88.  
  89. DTIC
  90. Cameron Station
  91. Alexandria,  VA  22314
  92. (703) 274-7633
  93.  
  94. The general public can order copies through the National Technical Information 
  95. Service:
  96.  
  97. NTIS, Commerce Dept.
  98. 5285 Port Royal Rd.
  99. Springfield, VA  22161
  100. (703) 487-4650
  101.  
  102. Electronic copies are available for downloading from the Ada IC Bulletin
  103. Board, (703) 614-0215, and from the AJPO host (ajpo.sei.cmu.edu) on the
  104. Defense Data Network.
  105.  
  106.  
  107.  
  108. AUTHORS AND ACKNOWLEDGEMENTS
  109.  
  110. The editor for this third version of Ada Quality and Style: Guidelines for
  111. Professional Programmers is Doug Smith. Kent Johnson managed the update
  112. project and the DoD Ada Joint Program Office provided the funding. As part of
  113. this update, a panel of distinguished reviewers was chosen from academia,
  114. government, and industry. Their contributions and efforts to improve this
  115. document are greatly appreciated:
  116.  
  117.  
  118.  
  119. Ms. Christine Braun             GTE Federal Systems
  120.  
  121. Dr. Charles B. Engle, Jr.       Department of Computer Science
  122.                                 Florida Institute of Technology
  123.  
  124. Dr. Michael B. Feldman          Department of Electrical Engineering and
  125.                                   Computer Science
  126.                                 George Washington University
  127.  
  128. Dr. Robert Firth                Software Engineering Institute
  129.                                 Carnegie-Mellon University
  130.  
  131. Ms. Eileen S. Quann             FASTRAK Training, Inc.
  132.  
  133. Dr. Charles H. Sampson          Computer Sciences Corporation
  134.  
  135. Mr. Ed Seidewitz                NASA, Goddard Space Flight Center
  136.  
  137. Lisa Finneran, Rick Kirk, and Eric Marshall also served as Software
  138. Productivity Consortium reviewers. Mike Cochran made the majority of changes
  139. to the Concurrency chapter and Alex Blakemore authored or rewrote several
  140. guidelines for this version. Lyn Uzzle helped fix the menu-driven interface
  141. example. Public comment was invited, and Fred J. Roeber and Bob Crispen
  142. provided a considerable amount of suggestions.
  143.  
  144. Susan Robanos provided technical editing, Debra Morgan provided word 
  145. processing, and Tina Medina provided clean proofing.
  146.  
  147. A special thanks to GrammaTech, Inc. who made their Ada#ASSURED product 
  148. available. All of the examples were formatted in whole or in part using their 
  149. tool.
  150.  
  151. This version builds on the success of the authors and contributors to previous 
  152. versions. The acknowledgements from those efforts are included here.
  153.  
  154. The authors for the second edition were Kent Johnson, Elisa Simmons, and Fred 
  155. Stluka. Contributors were Alex Blakemore and Robert Hofkin. Reviewers included 
  156. Alex Blakemore, Rick Conn, Tim Harrison, Dave Nettles, and Doug Smith. 
  157. Additional support was provided by Vicki Clatterbuck and Leslie Hubbard.
  158.  
  159. The following people contributed to an instantiation of the first edition's 
  160. guidelines: Richard Bechtold, Pete Bloodgood, Shawna Gregory, Tim Powell, Dave 
  161. Nettles, Kevin Schaan, Doug Smith, and Perry Tsacoumis.
  162.  
  163. Special thanks are extended to Loral for providing feedback in the form of 
  164. their Software Productivity Laboratory Ada Standards.
  165.  
  166. The Consortium would also like to acknowledge those involved in the first 
  167. edition. The authors were Richard Drake, Samuel Gregory, Margaret Skalko, and 
  168. Lyn Uzzle. Paul Cohen managed the project. The contributors and reviewers were 
  169. Mark Dowson, John Knight, Henry Ledgard, and Robert Mathis.
  170.  
  171. Additional supporters included Bruce Barnes, Alex Blakemore, Terry Bollinger,
  172. Charles Brown, Neil Burkhard, William Carlson, Susan Carroll, John
  173. Chludzinski, Vicki Clatterbuck, Robert Cohen, Elizabeth Comer, Daniel Cooper,
  174. Jorge Diaz-Herrera, Tim Harrison, Robert Hofkin, Allan Jaworski, Edward Jones,
  175. John A.N. Lee, Eric Marshall, Charles Mooney, John Moore, Karl Nyberg, Arthur
  176. Pyster, Samuel Redwine, Jr., William Riddle, Lisa Smith, Fred Stluka, Kathy
  177. Velick, David Weiss, and Howard Yudkin.
  178.  
  179.  
  180.  
  181. CONTENTS
  182.  
  183.  
  184.  
  185.  
  186. CHAPTER 1 Introduction                                                    1
  187.  
  188. 1.1     HOW TO USE THIS BOOK                                              2
  189.  
  190. 1.2     TO THE NEW Ada PROGRAMMER                                         2
  191.  
  192. 1.3     TO THE EXPERIENCED Ada PROGRAMMER                                 3
  193.  
  194. 1.4     TO THE SOFTWARE PROJECT MANAGER                                   3
  195.  
  196. 1.5     TO CONTRACTING AGENCIES AND STANDARDS ORGANIZATIONS               4
  197.  
  198. CHAPTER 2 Source Code Presentation                                        5
  199.  
  200. 2.1     CODE FORMATTING                                                   5
  201.  
  202. 2.2     SUMMARY                                                          15
  203.  
  204. CHAPTER 3 Readability                                                    17
  205.  
  206. 3.1     SPELLING                                                         17
  207.  
  208. 3.2     NAMING CONVENTIONS                                               20
  209.  
  210. 3.3     COMMENTS                                                         24
  211.  
  212. 3.4     USING TYPES                                                      35
  213.  
  214. 3.5     SUMMARY                                                          37
  215.  
  216. CHAPTER 4 Program Structure                                              41
  217.  
  218. 4.1     HIGH-LEVEL STRUCTURE                                             41
  219.  
  220. 4.2     VISIBILITY                                                       46
  221.  
  222. 4.3     EXCEPTIONS                                                       50
  223.  
  224. 4.4     SUMMARY                                                          52
  225.  
  226. CHAPTER 5 Programming Practices                                          55
  227.  
  228. 5.1     OPTIONAL PARTS OF THE SYNTAX                                     55
  229.  
  230. 5.2     PARAMETER LISTS                                                  58
  231.  
  232. 5.3     TYPES                                                            60
  233.  
  234. 5.4     DATA STRUCTURES                                                  63
  235.  
  236. 5.5     EXPRESSIONS                                                      66
  237.  
  238. 5.6     STATEMENTS                                                       69
  239.  
  240. 5.7     VISIBILITY                                                       77
  241.  
  242. 5.8     USING EXCEPTIONS                                                 80
  243.  
  244. 5.9     ERRONEOUS EXECUTION                                              83
  245.  
  246. 5.10    SUMMARY                                                          87
  247.  
  248. CHAPTER 6 Concurrency                                                    91
  249.  
  250. 6.1     TASKING                                                          91
  251.  
  252. 6.2     COMMUNICATION                                                    96
  253.  
  254. 6.3     TERMINATION                                                     104
  255.  
  256. 6.4     SUMMARY                                                         107
  257.  
  258. CHAPTER 7 Portability                                                   109
  259.  
  260. 7.1     FUNDAMENTALS                                                    110
  261.  
  262. 7.2     NUMERIC TYPES AND EXPRESSIONS                                   113
  263.  
  264. 7.3     STORAGE CONTROL                                                 116
  265.  
  266. 7.4     TASKING                                                         117
  267.  
  268. 7.5     EXCEPTIONS                                                      118
  269.  
  270. 7.6     REPRESENTATION CLAUSES AND IMPLEMENTATION#DEPENDENT 
  271.     FEATURES                                                        119
  272.  
  273. 7.7     INPUT/OUTPUT                                                    122
  274.  
  275. 7.8     SUMMARY                                                         124
  276.  
  277. CHAPTER 8 Reusability                                                   127
  278.  
  279. 8.1     UNDERSTANDING AND CLARITY                                       128
  280.  
  281. 8.2     ROBUSTNESS                                                      130
  282.  
  283. 8.3     ADAPTABILITY                                                    136
  284.  
  285. 8.4     INDEPENDENCE                                                    147
  286.  
  287. 8.5     SUMMARY                                                         151
  288.  
  289. CHAPTER 9 Performance                                                   153
  290.  
  291. 9.1     IMPROVING EXECUTION SPEED                                       153
  292.  
  293. 9.2     SUMMARY                                                         156
  294.  
  295. CHAPTER 10 Complete Examples                                            157
  296.  
  297. 10.1    MENU-DRIVEN USER INTERFACE                                      157
  298.  
  299. 10.2    LINE-ORIENTED PORTABLE DINING PHILOSOPHERS EXAMPLE              165
  300.  
  301. 10.3    WINDOW-ORIENTED PORTABLE DINING PHILOSOPHERS EXAMPLE            170
  302.  
  303. APPENDIX A Map from Ada Language Reference Manual to Guidelines         179
  304.  
  305. REFERENCES                                                              185
  306.  
  307. BIBLIOGRAPHY                                                            189
  308.  
  309. INDEX                                                                   193
  310.  
  311.  
  312.  
  313.  
  314. CHAPTER 1
  315. Introduction
  316.  
  317. This book is intended to help the computer professional produce better Ada
  318. programs. It presents a set of specific guidelines for using the powerful
  319. features of Ada in a disciplined manner. Each guideline consists of a concise
  320. statement of the principles that should be followed, and a rationale
  321. explaining why following the guideline is important. In most cases, an example
  322. of the use of the guideline is provided, and in some cases a further example
  323. is included showing the consequences of violating the guideline. Possible
  324. exceptions to the application of the guideline are explicitly noted, and
  325. further explanatory notes, including notes on how the guideline could be
  326. automated by a tool, are provided where appropriate. Many of the guidelines
  327. are specific enough to be adopted as corporate or project programming
  328. standards.  Others require a managerial decision on a particular instantiation
  329. before they can be used as standards. In such cases, a sample instantiation is
  330. presented and used throughout the examples. Such instantiations should be
  331. recognized as weaker recommendations than the guidelines themselves. These
  332. issues are discussed in Section of this introduction. Other sections of the
  333. introduction discuss how this book should be used by various software
  334. development personnel.
  335.  
  336. Ada was designed to support the development of high-quality, reliable,
  337. reusable, and portable software. For a number of reasons, no programming 
  338. language can ensure the achievement of these desirable objectives on its own. 
  339. For example, programming must be embedded in a disciplined development process 
  340. that addresses requirements analysis, design, implementation, verification, 
  341. validation, and maintenance in an organized way. The use of the language must 
  342. conform to good programming practices based on well established software 
  343. engineering principles. This book is intended to help bridge the gap between 
  344. these principles and the actual practice of programming in Ada. 
  345.  
  346. Clear, readable, understandable source text eases program evolution,
  347. adaptation, and maintenance. First, such source text is more likely to be
  348. correct and reliable. Second, effective code adaptation is a prerequisite to
  349. code reuse, a technique that has the potential for drastic reductions in
  350. system development cost. Easy adaptation requires a thorough understanding of
  351. the software; this is considerably facilitated by clarity. Finally, since
  352. maintenance (really evolution) is a costly process that continues throughout
  353. the life of a system, clarity plays a major role in keeping maintenance costs
  354. down. Over the entire life cycle, code has to be read and understood far more
  355. often than it is written; the investment of writing readable, understandable
  356. code is thus well worthwhile. Many of the guidelines in this book are designed
  357. to promote clear source text.
  358.  
  359. There are two main aspects of code clarity: 1) Careful and consistent layout
  360. of the source text on the page or the screen can enhance readability
  361. dramatically; 2) Careful attention to the structure of code can make it easier
  362. to understand. This is true both on the small scale (e.g., by careful choice
  363. of identifier names or by disciplined use of loops) and on the large scale
  364. (e.g., by proper use of packages). These guidelines treat both layout and
  365. structure.
  366.  
  367. Comments in source text are a controversial issue. There are arguments both
  368. for and against the view that comments enhance readability. The biggest
  369. problem with comments in practice is that people often fail to update them
  370. when the associated source text is changed, thereby making the commentary
  371. misleading.  Commentary should be reserved for expressing needed information
  372. that cannot be expressed in code and highlighting cases where there are
  373. overriding reasons to violate one of the guidelines. If possible, source text
  374. should use self-explanatory names for objects and program units; and it should
  375. use simple, understandable program structures so that little additional
  376. commentary is needed. The extra effort in selecting (and entering) appropriate
  377. names and the extra thought needed to design clean and understandable program
  378. structures are fully justified.
  379.  
  380. Programming texts often fail to discuss overall program structure; Chapter 4 
  381. addresses this. The majority of the guidelines in that chapter are concerned 
  382. with the application of sound software engineering principles such as 
  383. information hiding and separation of concerns. The chapter is neither a 
  384. textbook on nor an introduction to these principles; rather, it indicates how 
  385. they can be realized using the features of Ada.
  386.  
  387. A number of other guidelines are particularly concerned with reliability and
  388. portability issues. They counsel avoidance of language features and
  389. programming practices that either depend on properties not defined in Ada or
  390. on properties that may vary from implementation to implementation. Some of
  391. these guidelines, such as the one forbidding dependence on expression
  392. evaluation order, should never be violated. Others may have to be violated in
  393. special situations such as interfacing to other systems. This should only be
  394. done after careful deliberation, and such violations should be prominently
  395. indicated. Performance constraints are often offered as an excuse for unsafe
  396. programming practices; this is rarely a sufficient justification.
  397.  
  398. Software tools could be used to enforce, encourage, or check conformance to 
  399. many of the guidelines. At present, such tools for Ada primarily consist of 
  400. code formatters or syntax directed editors. Existing code formatters are often 
  401. parameterizable and can be instantiated to lay out code in a way consistent 
  402. with many of the guidelines in this book.
  403.  
  404. This book is intended for those involved in the actual development of software
  405. systems written in Ada. The following subsections discuss how to make the most
  406. effective use of the material presented. Readers with different levels of Ada
  407. experience and different roles in a software project will need to use the book
  408. in different ways. Specific comments to three broad categories of software
  409. development personnel are addressed: inexperienced Ada programmers,
  410. experienced Ada programmers, and software development managers.
  411.  
  412. 1.1     HOW TO USE THIS BOOK
  413.  
  414. There are a number of ways in which this book can be used: as a reference on
  415. good Ada style; as a comprehensive list of guidelines which will contribute to
  416. better Ada programs; or as a reference work to consult about using specific
  417. features of the language. The book contains many guidelines, some of which are
  418. quite complex. Learning them all at the same time should not be necessary; it
  419. is unlikely that you will be using all the features of the language at once.
  420. However, it is recommended that all programmers (and, where possible, other
  421. Ada project staff) make an effort to read and understand Chapters 2, 3, and 4
  422. and Chapter 5 up to Section 5.7. Some of the material is quite difficult (for
  423. example, Section 4.2 which discusses visibility), but it covers issues which
  424. are fundamental to the effective use of Ada and is important for any software
  425. professional involved in building Ada systems.
  426.  
  427. The remainder of the book covers relatively specific issues. Exceptions and
  428. erroneous execution is covered at the end of Chapter 5; and tasking,
  429. portability, and reuse is covered in Chapters 6, 7, and 8 respectively. You
  430. should be aware of the content of this part of the book. You may be required
  431. to follow the guidelines presented in it, but you could defer more detailed
  432. study until needed. Meanwhile, it can serve as useful reference material about
  433. specific Ada features; for example, the discussion of floating point numbers
  434. in the chapter on portability.
  435.  
  436. This book is not intended as an introductory text on Ada or as a complete 
  437. manual of the Ada language. It is assumed that you already know the syntax of 
  438. Ada and have a rudimentary understanding of the semantics. With such a 
  439. background, you should find the guidelines useful, informative, and often 
  440. enlightening.
  441.  
  442. If you are learning Ada you should equip yourself with a comprehensive
  443. introduction to the language such as Barnes (1989) or Cohen (1986). The Ada
  444. Language Reference Manual (Department of Defense 1983) should be regarded as a
  445. crucial companion to this book. The majority of guidelines reference the
  446. sections of the Ada Language Reference Manual that define the language
  447. features being discussed. Appendix A cross references sections of the Ada
  448. Language Reference Manual to the guidelines.
  449.  
  450. Throughout the book, references are given to other sources of information
  451. about Ada style and other Ada issues. The references are listed at the end of
  452. the book, followed by a bibliography which includes them and other relevant
  453. sources consulted during the book's preparation.
  454.  
  455. 1.2     TO THE NEW Ada PROGRAMMER
  456.  
  457. At first sight, Ada offers a bewildering variety of features. It is a powerful
  458. tool intended to solve difficult problems, and almost every feature has a
  459. legitimate application in some context. This makes it especially important to
  460. use Ada's features in a disciplined and organized way. The guidelines in this
  461. book forbid the use of few Ada features. Rather, they show how the features
  462. can be systematically deployed to write clear, high-quality programs.
  463. Following the guidelines will make learning Ada easier and help you to master
  464. its apparent complexity. From the beginning, you can write programs that
  465. exploit the best features of the language in the way that the designers
  466. intended.
  467.  
  468. Programmers experienced in using another programming language are often
  469. tempted to use Ada as if it were their familiar language but with irritating
  470. syntactic differences. This pitfall should be avoided at all costs; it can
  471. lead to convoluted code that subverts exactly those aspects of Ada that make
  472. it so suitable for building high-quality systems. You must learn to "think
  473. Ada"; following the guidelines in this book and reading the examples of their
  474. use will help you to do this as quickly and painlessly as possible.
  475.  
  476. To some degree, novice programmers learning Ada have an advantage. Following
  477. the guidelines from the beginning helps in developing a clear programming
  478. style that effectively exploits the language. If you are in this category, it
  479. is recommended that you adopt the guidelines for those exercises you perform
  480. as part of learning Ada. Initially, developing sound programming habits by
  481. concentrating on the guidelines themselves, and their supporting examples, is
  482. more important than understanding the rationale for each guideline. Note that
  483. each chapter ends with a summary of the guidelines it contains.
  484.  
  485. The rationale for many of the guidelines help experienced programmers 
  486. understand and accept the suggestions presented in the guideline. Some of the 
  487. guidelines themselves are also written for the experienced programmer who must 
  488. make engineering tradeoffs. This is especially true in the areas of 
  489. portability, reusability, and performance. These more difficult guidelines and 
  490. rationale will make you aware of the issues affecting each programming 
  491. decision. You can then use that awareness to recognize the engineering 
  492. tradeoffs that you will eventually be asked to make when you are the 
  493. experienced Ada programmer.
  494.  
  495. 1.3     TO THE EXPERIENCED Ada PROGRAMMER
  496.  
  497. As an experienced programmer you are already writing code that conforms to
  498. many of the guidelines in this book. In some areas, however, you may have
  499. adopted a personal programming style that differs from that presented here,
  500. and you might be reluctant to change. Carefully review those guidelines that
  501. are inconsistent with your current style, make sure that you understand their
  502. rationale, and consider adopting them. The overall set of guidelines in this
  503. book embodies a consistent approach to producing high-quality programs that
  504. would be weakened by too many exceptions.
  505.  
  506. Another important reason for general adoption of common guidelines is
  507. consistency. If all the staff of a project write source text in the same
  508. style, many critical project activities are easier. Consistent code simplifies
  509. formal and informal code reviews, system integration, within-project code
  510. reuse, and the provision and application of supporting tools. In practice,
  511. corporate or project standards may require deviations from the guidelines to
  512. be explicitly commented, so adopting a nonstandard approach may require extra
  513. work.
  514.  
  515. 1.4     TO THE SOFTWARE PROJECT MANAGER
  516.  
  517. Technical management plays a key role in ensuring that the software produced
  518. in the course of a project is correct, reliable, maintainable, and portable.
  519. Management must create a project-wide commitment to the production of
  520. high-quality code; define project-specific coding standards and guidelines;
  521. foster an understanding of why uniform adherence to the chosen coding
  522. standards is critical to product quality; and establish policies and
  523. procedures to check and enforce that adherence. The guidelines contained in
  524. this book can aid such an effort.
  525.  
  526. An important activity for managers is the definition of coding standards for a
  527. project or organization. These guidelines do not, in themselves, constitute a
  528. complete set of standards; however, they can serve as a basis for them. A
  529. number of guidelines indicate a range of decisions, but they do not prescribe
  530. a particular decision. For example, the second guideline in the book
  531. (Guideline ) advocates using a consistent number of spaces for indentation and
  532. indicates in the rationale that 2 to 4 spaces would be reasonable. With your
  533. senior technical staff, you should review each such guideline and arrive at a
  534. decision about its instantiation that will constitute your project or
  535. organizational standard.
  536.  
  537. Two other areas require managerial decisions about standardization. Guideline
  538. advises you to avoid arbitrary abbreviations in object or unit names. You
  539. should prepare a glossary of acceptable abbreviations for a project that
  540. allows the use of shorter versions of application-specific terms (e.g., FFT
  541. for Fast Fourier Transform or SPN for Stochastic Petri Net). You should keep
  542. this glossary short and restrict it to terms which need to be used frequently
  543. as part of names. Having to refer continually to an extensive glossary to
  544. understand source text makes it hard to read.
  545.  
  546. The portability guidelines given in Chapter 7 need careful attention.
  547. Adherence to them is important even if the need to port the resulting software
  548. is not currently foreseen. Following the guidelines improve the potential
  549. reusability of the resulting code in projects that use different Ada
  550. implementations. You should insist that when particular project needs force
  551. the relaxation of some of the portability guidelines, nonportable features of
  552. the source text are prominently indicated. Observing the Chapter 7 guidelines
  553. requires definition and standardization of project- or organization-specific
  554. numeric types to use in place of the (potentially nonportable) predefined
  555. numeric types.
  556.  
  557. Your decisions on standardization issues should be incorporated in a project
  558. or organization coding standards document.
  559.  
  560. With coding standards in place, you need to ensure adherence to them. Probably 
  561. the most important aspect of this is gaining the wholehearted commitment of 
  562. your programming staff to use them. Given this commitment, and the example of 
  563. high-quality Ada being produced by your programmers, it will be far easier to
  564. conduct effective formal code reviews that check compliance to project 
  565. standards.
  566.  
  567. Consistent coding standards work well with automatic tool support. If you have
  568. a tools group in your project or organization, they can be tasked to acquire
  569. or develop tools to support your standards. It is very cost effective to use
  570. tools to enforce standards. Where tools cannot be used to automatically modify
  571. code to conform to standards, they can often be used to at least check
  572. conformance.  See the automation notes sections associated with many of the
  573. guidelines.
  574.  
  575. Some general issues concerning the management of Ada projects are discussed by 
  576. Foreman and Goodenough (1987).
  577.  
  578. 1.5     TO CONTRACTING AGENCIES AND STANDARDS ORGANIZATIONS
  579.  
  580. The guidelines in this document are not intended to stand alone as a standard.
  581. It is not even clear in some cases that a guideline could be enforced since it
  582. is only intended to make the engineer aware of tradeoffs.  In other cases, a
  583. choice still remains about a guideline, such as how many spaces to use for
  584. each level of indentation.
  585.  
  586. When a guideline is too general to show an example, the "instantiation"
  587. section of each guideline contains more specific guidelines.  These can be
  588. considered for a standard and are more likely to be enforceable.  Any
  589. organization that attempts to extract standards from this document needs to
  590. evaluate the complete context.  Each guideline works best when related
  591. guideines are practiced.  In isolation, a guideline may have little or no
  592. benefit.
  593.  
  594.  
  595.  
  596.  
  597. CHAPTER 2
  598. Source Code Presentation
  599.  
  600. The physical layout of source text on the page or screen has a strong effect
  601. on its readability. This chapter contains source code presentation guidelines
  602. intended to make the code more readable.
  603.  
  604. In addition to the general purpose guidelines, specific recommendations are 
  605. made in the "instantiation" sections. If you disagree with the specific 
  606. recommendations, you may want to adopt your own set of conventions that still 
  607. follow the general purpose guidelines. Above all, be consistent across your 
  608. entire project.
  609.  
  610. An entirely consistent layout is hard to achieve or check manually. Therefore
  611. you may prefer to automate layout with a tool for parameterized code
  612. formatting or incorporate the guidelines into an automatic coding template.
  613. Some of the guidelines and specific recommendations presented in this section
  614. cannot be enforced by a formatting tool because they are based on the
  615. semantics, not the syntax, of the Ada code. More details are given in the
  616. "automation notes" sections.
  617.  
  618. 2.1     CODE FORMATTING
  619.  
  620. The "code formatting" of Ada source code affects how the code looks, not what 
  621. the code does. Topics included here are horizontal spacing, indentation, 
  622. alignment, pagination, and line length. The most important guideline is to be 
  623. consistent throughout the compilation unit as well as the project.
  624.  
  625. 2.1.1   Horizontal Spacing
  626.  
  627. guideline
  628.  
  629. o       Use consistent spacing around delimiters.
  630.  
  631. o       Use the same spacing as you would in regular prose.
  632.  
  633. instantiation
  634.  
  635. Specifically, leave at least one blank space in the following places, as shown 
  636. in the examples throughout this book. More spaces may be required for the 
  637. vertical alignment recommended in subsequent guidelines.
  638.  
  639. -       Before and after the following delimiters and binary operators:
  640.             +      -      *      /      &
  641.             <      =      >      /=     <=     >=
  642.             :=     =>     |      ..
  643.             :
  644.             <>
  645.  
  646. -       Outside of the quotes for string (") and character (') literals,
  647. except where prohibited.
  648.  
  649. -       Outside, but not inside, of parentheses.
  650.  
  651. -       After commas (,) and semicolons (;).
  652.  
  653. Do not leave any blank spaces in the following places, even if this conflicts 
  654. with the above recommendation.
  655.  
  656. -       After the plus (+) and minus (-) signs when used as unary operators.
  657.  
  658. -       After a function call.
  659.  
  660. -       Inside of label delimiters (<< >>).
  661.  
  662. -       Before and after the apostrophe (') and period (.)
  663.  
  664. -       Between multiple consecutive opening or closing parentheses.
  665.  
  666. -       Before commas (,) and semicolons (;).
  667.  
  668. When superfluous parentheses are omitted because of operator precedence rules, 
  669. spaces may optionally be removed around the highest precedence operators in 
  670. that expression.
  671.  
  672. example
  673.  
  674. Default_String : constant String :=
  675.       "This is the long string returned by" &
  676.       " default.  It is broken into multiple" &
  677.       " Ada source lines for convenience.";
  678.  
  679. type Signed_Whole_16 is range -2**15 .. 2**15 - 1;
  680. type Address_Area    is array (Natural range <>) of Signed_Whole_16;
  681.  
  682. Register : Address_Area (16#7FF0# .. 16#7FFF#);
  683. Memory   : Address_Area (       0 .. 16#7FEC#);
  684.  
  685. Register(Pc) := Register(A);
  686.  
  687. X := Signed_Whole_16(Radius * Sin(Angle));
  688.  
  689. Register(Index) := Memory(Base_Address + Index * Element_Length);
  690.  
  691. Get(Value => Sensor);
  692.  
  693. Error_Term := 1.0 - (Cos(Theta)**2 + Sin(Theta)**2);
  694.  
  695. Z      := X**3;
  696. Y      := C * X + B;
  697. Volume := Length * Width * Height;
  698.  
  699.  
  700. rationale
  701.  
  702. It is a good idea to use white space around delimiters and operators because
  703. they are typically short (one or two character) sequences that can easily get
  704. lost among the longer keywords and identifiers. Putting white space around
  705. them makes them stand out. Consistency in spacing also helps make the source
  706. code easier to scan visually.
  707.  
  708. However, many of the delimiters (commas, semicolons, parentheses, etc.) are
  709. familiar as normal punctuation marks. It is distracting to see them spaced
  710. differently in a computer program than in normal text. Therefore, they should
  711. be spaced the same (no spaces before commas and semicolons, no spaces inside
  712. of parentheses, etc.).
  713.  
  714. exception
  715.  
  716. The one notable exception is the colon (:). In Ada, it is useful to use the
  717. colon as a tabulator or a column separator (see Guideline ). In this context,
  718. it makes sense to put spaces before and after the colon, rather than only
  719. after as in normal text.
  720.  
  721. automation notes
  722.  
  723. The guidelines in this section are easily enforced with an automatic code 
  724. formatter.
  725.  
  726. 2.1.2   Indentation
  727.  
  728. guideline
  729.  
  730. o       Indent and align nested control structures, continuation lines, and 
  731. embedded units consistently. 
  732.  
  733. o       Distinguish between indentation for nested control structures and for 
  734. continuation lines.
  735.  
  736. o       Use spaces for indentation, not the tab character (Nissen and Wallis 
  737. 1984, w2.2).
  738.  
  739. instantiation
  740.  
  741. Specifically, the following indentation conventions are recommended, as shown 
  742. in the examples throughout this book. Note that the minimum indentation is 
  743. described. More spaces may be required for the vertical alignment recommended 
  744. in subsequent guidelines.
  745.  
  746. -       Use the recommended paragraphing shown in the Ada Language Reference 
  747. Manual (Department of Defense 1983).
  748.  
  749. -       Use three spaces as the basic unit of indentation for nesting.
  750.  
  751. -       Use two spaces as the basic unit of indentation for continuation lines.
  752.  
  753. A label is outdented three spaces. A continuation line is indented two spaces:
  754.  
  755. begin
  756. <<label>>                            | <long statement with line break>
  757.    <statement>                       |   <trailing part of same statement>
  758. end;
  759.  
  760. The if statement and the plain loop:
  761.  
  762.    if <condition> then               | <name>:
  763.       <statements>                   |    loop
  764.    elsif <condition> then            |       <statements>
  765.       <statements>                   |       exit when <condition>;
  766.    else                              |       <statements>
  767.       <statements>                   |    end loop <name>;
  768.    end if;                           |
  769.  
  770. Loops with the for and while iteration schemes:
  771.  
  772.    <name>:                           | <name>:
  773.       for <scheme> loop              |    while <condition> loop
  774.      <statements>                |       <statements>
  775.       end loop <name>;               |    end loop <name>;
  776.  
  777. The block and the case statement as recommended in the Ada Language Reference 
  778. Manual (Department of Defense 1983):
  779.  
  780.    <name>:                           | case <expression> is
  781.       declare                        |    when <choice> =>
  782.      <declarations>              |       <statements>
  783.       begin                          |    when <choice> =>
  784.      <statements>                |       <statements>
  785.       exception                      |    when others =>
  786.      when <choice> =>            |       <statements>
  787.         <statements>             | end case;  --<comment>
  788.      when others =>              |
  789.         <statements>             |
  790.       end <name>;                    |
  791.  
  792. These case statements save space over the the Ada Language Reference Manual 
  793. (Department of Defense 1983) recommendation and depend on very short statement 
  794. lists, respectively. Whichever you choose, be consistent.
  795.  
  796.    case <expression> is              | case <expression> is
  797.    when <choice> =>                  |    when <choice> => <statements>
  798.     <statements>                 |                     <statements>
  799.    when <choice> =>                  |    when <choice> => <statements>
  800.     <statements>                 |    when others   => <statements>
  801.    when others =>                    | end case;
  802.     <statements>                 |
  803.    end case;                         |
  804.  
  805. The various forms of selective wait and the timed and conditional entry calls:
  806.  
  807.    select                            | select
  808.       when <guard> =>                |    <entry call>;
  809.      <accept statement>          |    <statements>
  810.      <statements>                | or
  811.    or                                |    delay <interval>;
  812.       <accept statement>             |    <statements>
  813.       <statements>                   | end select;
  814.    or                                |
  815.       when <guard> =>                |
  816.      delay <interval>;           |
  817.      <statements>                |
  818.    or                                | select
  819.       when <guard> =>                |    <entry call>;
  820.      terminate;                  |    <statements>
  821.    else                              | else
  822.       <statements>                   |    <statements>
  823.    end select;                       | end select;
  824.  
  825. The accept statement and a subunit:
  826.  
  827.    accept <specification> do         | separate (<parent unit>)
  828.       <statements>                   | <proper body>
  829.    end <name>;                       |
  830.  
  831. Proper bodies of program units:
  832.  
  833.    procedure <specification> is      | package body <name> is
  834.       <declarations>                 |    <declarations>
  835.    begin                             | begin
  836.       <statements>                   |    <statements>
  837.    exception                         | exception
  838.       when <choice> =>               |    when <choice> =>
  839.      <statements>                |       <statements>
  840.    end <name>;                       | end <name>;
  841.                      |
  842.    function  <specification>         | task body <name> is
  843.      return  <type name> is          |    <declarations>
  844.       <declarations>                 | begin
  845.    begin                             |    <statements>
  846.       <statements>                   | exception
  847.    exception                         |    when <choice> =>
  848.       when <choice> =>               |       <statements>
  849.      <statements>                | end <name>;
  850.    end <name>;                       |
  851.  
  852. Context clauses on compilation units are arranged as a table. Generic formal 
  853. parameters do not obscure the unit itself. Function, package, and task 
  854. specifications use standard indentation:
  855.  
  856.    with <name>;                      | function  <specification>
  857.    with <name>;                      |   return <type>;
  858.    with <name>;                      |
  859.                      | package <name> is
  860.    use  <name>;                      |    <declarations>
  861.                      | private
  862.    <compilation unit>                |    <declarations>
  863.                      | end <name>;
  864.                      |
  865.    generic                           | task type <name> is
  866.       <formal parameters>            |    <entry declarations>
  867.    <compilation unit>                | end <name>;
  868.  
  869. Instantiations of generic units and record indentation:
  870.  
  871.    procedure <name> is               |type ... is
  872.       new <generic name> <actuals>   |   record
  873.                      |      <component list>
  874.    function <name> is                |      case <discriminant name> is
  875.       new <generic name> <actuals>|            when <choice> =>
  876.                      |            <component list>
  877.    package <name> is                 |         when <choice> =>
  878.       new <generic name> <actuals>   |            <component list>
  879.                      |      end case;
  880.                      |   end record;
  881.  
  882. Indentation for record alignment:
  883.  
  884.    for <name> use
  885.       record <alignment clause>
  886.      <component clause>
  887.       end record;
  888.  
  889. example
  890.  
  891. Default_String : constant String :=
  892.       "This is the long string returned by" &
  893.       " default.  It is broken into multiple" &
  894.       " Ada source lines for convenience.";
  895.  
  896. loop
  897.  
  898.    if Input_Found then
  899.       Count_Characters;
  900.  
  901.    else  --not Input_Found
  902.       Reset_State;
  903.       Character_Total :=
  904.         First_Part_Total  * First_Part_Scale_Factor  +
  905.         Second_Part_Total * Second_Part_Scale_Factor +
  906.         Default_String'Length + Delimiter_Size;
  907.    end if;
  908.  
  909. end loop;
  910.  
  911. rationale
  912.  
  913. Indentation improves the readability of the code because it gives the reader a
  914. visual indicator of the program structure. The levels of nesting are clearly
  915. identified by indentation and the first and last keywords in a construct can
  916. be matched visually.
  917.  
  918. While there is much discussion on the number of spaces to indent, the reason 
  919. for indentation is code clarity. The fact that the code is indented 
  920. consistently is more important than the number of spaces used for indentation.
  921.  
  922. Additionally, in Section 1.5, the Ada Language Reference Manual says that the
  923. layout shown in the examples and syntax rules in the Ada Language Reference
  924. Manual is the recommended code layout to be used for Ada programs. "The syntax
  925. rules describing structured constructs are presented in a form that
  926. corresponds to the recommended paragraphing. ... Different lines are used for
  927. parts of a syntax rule if the corresponding parts of the construct described
  928. by the rule are intended to be on different lines. ... It is recommended that
  929. all indentation be by multiples of a basic step of indentation (the number of
  930. spaces for the basic step is not defined)."
  931.  
  932. It is important to indent continuation lines differently from nested control 
  933. structures to make them visually distinct. This prevents them from obscuring 
  934. the structure of the code as the user scans it.
  935.  
  936. Indenting with spaces is more portable than indenting with tabs because tab 
  937. characters are displayed differently by different terminals and printers.
  938.  
  939. automation notes
  940.  
  941. The guidelines in this section are easily enforced with an automatic code 
  942. formatter.
  943.  
  944. 2.1.3   Alignment of Operators
  945.  
  946. guideline
  947.  
  948. o       Align operators vertically to emphasize local program structure and 
  949. semantics.
  950.  
  951. example 
  952.  
  953. if Slot_A >= Slot_B then
  954.    Temporary := Slot_A;
  955.    Slot_A    := Slot_B;
  956.    Slot_B    := Temporary;
  957. end if;
  958.  
  959. Numerator   := B**2 - 4.0 * A * C;
  960. Denominator := 2.0 * A;
  961.  
  962. Solution_1 := -B + Square_Root(Numerator / Denominator);
  963. Solution_2 :=  B + Square_Root(Numerator / Denominator);
  964.  
  965. X := A * B +
  966.      C * D +
  967.      E * F;
  968.  
  969. Y := (A   * B + C) +  -- basic equation
  970.      (2.0 * D - E) -  --
  971.      3.5;             -- account for error factor
  972.  
  973. rationale
  974.  
  975. Alignment makes it easier to see the position of the operators and, therefore, 
  976. puts visual emphasis on what the code is doing.
  977.  
  978. The use of lines and spacing on long expressions can emphasize terms, 
  979. precedence of operators, and other semantics. It can also leave room for 
  980. highlighting comments within an expression.
  981.  
  982. exceptions
  983.  
  984. If vertical alignment of operators forces a statement to be broken over two 
  985. lines, and especially if the break is at an inappropriate spot, it may be 
  986. preferable to relax the alignment guideline.
  987.  
  988. automation notes
  989.  
  990. The last example above shows a type of "semantic alignment" which is not
  991. typically enforced or even preserved by automatic code formatters. If you
  992. break expressions into semantic parts and put each on a separate line, beware
  993. of using a code formatter later. It is likely to move the entire expression to
  994. a single line and accumulate all the comments at the end. However, there are
  995. some formatters which are intelligent enough to leave a line break intact when
  996. the line contains a comment.  A good formatter will recognize that the last
  997. example above does not violate the guidelines and would therefore preserve it
  998. as written.
  999.  
  1000. 2.1.4   Alignment of Declarations
  1001.  
  1002. guideline
  1003.  
  1004. o       Use vertical alignment to enhance the readability of declarations.
  1005.  
  1006. o       Provide at most one declaration per line.
  1007.  
  1008. o       Indent all declarations in a single declarative part at the same level.
  1009.  
  1010. instantiation
  1011.  
  1012. For declarations not separated by blank lines, follow these alignment rules.
  1013.  
  1014. -       Align the colon delimeters.
  1015.  
  1016. -       Align the initialization delimeter, ":=".
  1017.  
  1018. -       When trailing comments are used, align the comment delimeter.
  1019.  
  1020. -     When the declaration overflows a line, break the line and add an
  1021. indentation level for those lines that wrap.  The preferred places to break,
  1022. in order are: 1) The comment delimeter; 2) The initialization delimeter; 3)
  1023. The colon delimeter.
  1024.  
  1025. -    For enumeration type declarations which do not fit on a single line,
  1026. put each literal on a separate line, using the next level of indentation.
  1027. When appropriate, semantically related literals can be arranged by row or
  1028. column to form a table.
  1029.  
  1030. example
  1031.  
  1032. Variable and constant declarations can be laid out in a table with columns 
  1033. separated by the symbols :, :=, and --
  1034.  
  1035. Prompt_Column : constant        := 40;
  1036. Question_Mark : constant String := " ? "; -- prompt on error input
  1037. Prompt_String : constant String := " ==> ";
  1038.  
  1039. If this results in lines that are too long, they can be laid out with each
  1040. part on a separate line with its unique indentation level.
  1041.  
  1042. subtype User_Response_Text_Frame is String (1 .. 72);
  1043.  
  1044. -- If the declaration needed a comment, it would fit here.
  1045. Input_Line_Buffer : User_Response_Text_Frame
  1046.        := Prompt_String &
  1047.       String'(1 .. User_Response_Text_Frame'Length -
  1048.                Prompt_String'Length => ' ');
  1049.  
  1050. Declarations of enumeration literals can be listed in one or more columns as:
  1051.  
  1052. type Op_Codes_In_Column is
  1053.       (Push,
  1054.        Pop,
  1055.        Add,
  1056.        Subtract,
  1057.        Multiply,
  1058.        Divide,
  1059.        Subroutine_Call,
  1060.        Subroutine_Return,
  1061.        Branch,
  1062.        Branch_On_Zero,
  1063.        Branch_On_Negative);
  1064.  
  1065. or, to save space:
  1066.  
  1067. type Op_Codes_Multiple_Columns is
  1068.       (Push,            Pop,                Add,
  1069.        Subtract,        Multiply,           Divide,
  1070.        Subroutine_Call, Subroutine_Return,  Branch,
  1071.        Branch_On_Zero,  Branch_On_Negative);
  1072.  
  1073. or, to emphasize related groups of values:
  1074.  
  1075. type Op_Codes_In_Table is
  1076.       (Push,            Pop,
  1077.        Add,             Subtract,          Multiply,          Divide,
  1078.        Subroutine_Call, Subroutine_Return,
  1079.        Branch,          Branch_On_Zero,    Branch_On_Negative);
  1080.  
  1081. rationale
  1082.  
  1083. Many programming standards documents require tabular repetition of names, 
  1084. types, initial values, and meaning in unit header comments. These comments are 
  1085. redundant and can become inconsistent with the code. Aligning the declarations 
  1086. themselves in tabular fashion (see the examples above) provides identical 
  1087. information to both compiler and reader, enforces at most one declaration per 
  1088. line, and eases maintenance by providing space for initializations and 
  1089. necessary comments. A tabular layout enhances readability, thus preventing 
  1090. names from "hiding" in a mass of declarations. This applies to type
  1091. declarations as well as object declarations.
  1092.  
  1093. automation notes
  1094.  
  1095. Most of the guidelines in this section are easily enforced with an automatic
  1096. code formatter. The one exception is the last enumerated type example, which
  1097. is laid out in rows based on the semantics of the enumeration literals. An
  1098. automatic code formatter will not be able to do this, and will likely move the
  1099. enumeration literals to different lines.  However, tools that are only
  1100. checking for violations of the guidelines should accept the tabular form of an
  1101. enumeration type declaration.
  1102.  
  1103. 2.1.5   More on Alignment
  1104.  
  1105. guideline
  1106.  
  1107. o       Align parameter modes and parentheses vertically. 
  1108.  
  1109. instantiation
  1110.  
  1111. Specifically it is recommended that you:
  1112.  
  1113. -       Place one formal parameter specification per line.
  1114.  
  1115. 12 Ada QUALITY AND STYLE
  1116.  
  1117. -       Vertically align parameter names, colons, the reserved word in, the 
  1118. reserved word out, and parameter types.
  1119.  
  1120. -       Place the first parameter specification on the same line as the 
  1121. subprogram or entry name. If any of the parameter types are forced beyond the 
  1122. line length limit, place the first parameter specification on a new line 
  1123. indented as for continuation lines.
  1124.  
  1125. example
  1126.  
  1127. procedure Display_Menu (Title   : in     String; 
  1128.             Options : in     Menus;
  1129.             Choice  :    out Alpha_Numerics);
  1130.  
  1131. or
  1132.  
  1133. procedure Display_Menu_On_Primary_Window
  1134.       (Title   : in     String;
  1135.        Options : in     Menus;
  1136.        Choice  :    out Alpha_Numerics);
  1137.  
  1138. or
  1139.  
  1140. procedure Display_Menu_On_Screen (
  1141.       Title   : in     String;
  1142.       Options : in     Menus;
  1143.       Choice  :    out Alpha_Numerics
  1144.       );
  1145.  
  1146. Aligning parentheses makes complicated relational expressions more clear:
  1147.  
  1148. if not (First_Character in Alpha_Numerics and then
  1149.     Valid_Option(First_Character))        then
  1150.  
  1151. rationale
  1152.  
  1153. This facilitates readability and understandability. Aligning parameter modes 
  1154. provides the effect of a table with columns for parameter name, mode, type, 
  1155. and, if necessary, parameter-specific comments. Vertical alignment of
  1156. parameters across subprograms within a compilation unit increases the 
  1157. readability even more.
  1158.  
  1159. note
  1160.  
  1161. Various options are available for subprogram layout. The second example above 
  1162. aligns all of the subprogram names and parameter names in a program.This has 
  1163. the disadvantage of occupying an unnecessary line where subprogram names are 
  1164. short and looking awkward if there is only one parameter.
  1165.  
  1166. The third example is a format commonly used to reduce the amount of editing
  1167. required when parameter lines are added, deleted, or reordered. The
  1168. parentheses don't have to be moved from line to line. However, the last
  1169. parameter line is the only one without a semicolon.
  1170.  
  1171. automation notes
  1172.  
  1173. Most of the guidelines in this section are easily enforced with an automatic
  1174. code formatter. The one exception is the last example, which shows vertical
  1175. alignment of parentheses to emphasize terms of an expression. This is
  1176. difficult to achieve with an automatic code formatter unless the relevant
  1177. terms of the expression can be determined strictly through operator
  1178. precedence.
  1179.  
  1180. 2.1.6   Blank Lines
  1181.  
  1182. guideline
  1183.  
  1184. o       Use blank lines to group logically related lines of text (NASA 1987).
  1185.  
  1186. example
  1187.  
  1188. if ... then
  1189.  
  1190.    for ... loop
  1191.       ...
  1192.    end loop;
  1193.  
  1194. end if;
  1195.  
  1196. This example separates different kinds of declarations with blank lines:
  1197.  
  1198. type Employee_Record is
  1199.    record
  1200.       Legal_Name    : Name;
  1201.       Date_Of_Birth : Date;
  1202.       Date_Of_Hire  : Date;
  1203.       Salary        : Money;
  1204.    end record;
  1205.  
  1206. type Day is
  1207.       (Monday,    Tuesday,   Wednesday, Thursday,  Friday,
  1208.        Saturday,  Sunday);
  1209.  
  1210. subtype Weekday is Day range Monday   .. Friday;
  1211. subtype Weekend is Day range Saturday .. Sunday;
  1212.  
  1213. rationale
  1214.  
  1215. When blank lines are used in a thoughtful and consistent manner, sections of 
  1216. related code are more visible to readers.
  1217.  
  1218. automation notes
  1219.  
  1220. Automatic formatters do not enforce this guideline well because the decision
  1221. on where to insert blank lines is a semantic one. However, many formatters
  1222. have the ability to leave existing blank lines intact. Thus, you can manually
  1223. insert the lines and not lose the effect when you run such a formatter.
  1224.  
  1225. 2.1.7   Pagination
  1226.  
  1227. guideline
  1228.  
  1229. o       Highlight the top of each package or task specification, the top of 
  1230. each program unit body, and the end statement of each program unit.
  1231.  
  1232. instantiation
  1233.  
  1234. Specifically, it is recommended that you:
  1235.  
  1236. -       Use file prologues, specification headers, and body headers to 
  1237. highlight those structures as recommended in Guideline .
  1238.  
  1239. -       Use a line of dashes, beginning at the same column as the current 
  1240. indentation to highlight the definition of subunits embedded in a declarative 
  1241. part.  Insert the line of dashes immediately before and immediately after the 
  1242. definition.
  1243.  
  1244. -       If two dashed lines are adjacent, omit the longer of the two.
  1245.  
  1246. example
  1247.  
  1248. with Basic_Types;
  1249.  
  1250. package body SPC_Numeric_Types is
  1251.  
  1252. ...
  1253.  
  1254.    ---------------------------------------------------------------------
  1255.    function Max
  1256.      (Left  : in     Basic_Types.Tiny_Integer;
  1257.       Right : in     Basic_Types.Tiny_Integer)
  1258.      return Basic_Types.Tiny_Integer is
  1259.    begin
  1260.       if Right < Left then
  1261.      return Left;
  1262.       else
  1263.      return Right;
  1264.       end if;
  1265.    end Max;
  1266.  
  1267.    ---------------------------------------------------------------------
  1268.    function Min
  1269.      (Left  : in     Basic_Types.Tiny_Integer;
  1270.       Right : in     Basic_Types.Tiny_Integer)
  1271.      return Basic_Types.Tiny_Integer is
  1272.    begin
  1273.       if Left < Right then
  1274.      return Left;
  1275.       else
  1276.      return Right;
  1277.       end if;
  1278.    end Min;
  1279.  
  1280.    ---------------------------------------------------------------------
  1281.  
  1282.    use Basic_Types;
  1283.  
  1284. begin  -- SPC_Numeric_Types
  1285.    Max_Tiny_Integer := Min(System_Max, Local_Max);
  1286.    Min_Tiny_Integer := Max(System_Min, Local_Min);
  1287.    -- ...
  1288. end SPC_Numeric_Types;
  1289.  
  1290. rationale
  1291.  
  1292. It is easy to overlook parts of program units that are not visible on the 
  1293. current page or screen. The page lengths of presentation hardware and software 
  1294. vary widely. By clearly marking the program's logical page boundaries (e.g., 
  1295. with a dashed line), you enable a reader to quickly check whether all of a 
  1296. program unit is visible. Such pagination also makes it easier to scan a large 
  1297. file quickly, looking for a particular program unit.
  1298.  
  1299. note
  1300.  
  1301. This guideline does not address code layout on the physical "page" because the
  1302. dimensions of such pages vary widely and no single guideline is appropriate.
  1303.  
  1304. automation notes
  1305.  
  1306. The guidelines in this section are easily enforced with an automatic code 
  1307. formatter.
  1308.  
  1309. 2.1.8   Number of Statements Per Line
  1310.  
  1311. guideline
  1312.  
  1313. o       Start each statement on a new line.
  1314.  
  1315. o       Write no more than one simple statement per line.
  1316.  
  1317. o       Break compound statements over multiple lines.
  1318.  
  1319. example
  1320.  
  1321. Use
  1322.  
  1323. if End_Of_File then
  1324.    Close_File;
  1325. else
  1326.    Get_Next_Record;
  1327. end if;
  1328.  
  1329. rather than
  1330.  
  1331. if End_Of_File then Close_File; else Get_Next_Record; end if;
  1332.  
  1333. exceptional case
  1334.  
  1335. Put("A=");    Natural_IO.Put(A);    New_Line;
  1336. Put("B=");    Natural_IO.Put(B);    New_Line;
  1337. Put("C=");    Natural_IO.Put(C);    New_Line;
  1338.  
  1339. rationale
  1340.  
  1341. A single statement on each line enhances the reader's ability to find 
  1342. statements and helps prevent statements being missed. Similarly, the structure 
  1343. of a compound statement is clearer when its parts are on separate lines.
  1344.  
  1345. note
  1346.  
  1347.  If a statement is longer than the remaining space on the line, continue it on 
  1348. the next line. This guideline includes declarations, context clauses, and 
  1349. subprogram parameters.
  1350.  
  1351. According to the Ada Language Reference Manual (Department of Defense 1983), 
  1352. "The preferred places for other line breaks are after semicolons."
  1353.  
  1354. exceptions
  1355.  
  1356. The example of Put and Newline statements shows a legitimate exception. This 
  1357. grouping of closely related statements on the same line makes the structural 
  1358. relationship between the groups clear.
  1359.  
  1360. automation notes
  1361.  
  1362. The guidelines in this section are easily enforced with an automatic code
  1363. formatter, with the single exception of the last example which shows a
  1364. semantic grouping of multiple statements onto a single line.
  1365.  
  1366. 2.1.9   Source Code Line Length
  1367.  
  1368. guideline
  1369.  
  1370. o       Adhere to a maximum line length limit for source code (Nissen and 
  1371. Wallis 1984, w2.3).
  1372.  
  1373. instantiation
  1374.  
  1375. Specifically, it is recommended that you:
  1376.  
  1377. -       Limit source code line lengths to a maximum of 72 characters.
  1378.  
  1379. rationale
  1380.  
  1381. When Ada code is ported from one system to another, there may be restrictions 
  1382. on the record size of source line statements possibly for one of the following 
  1383. reasons: some operating systems may not support variable length records for 
  1384. tape I/O or some printers and terminals support an 80-character line width with
  1385. no line-wrap. See further rationale in the note for Guideline .
  1386.  
  1387. Source code must sometimes be published for various reasons, and letter-size
  1388. paper is not as forgiving as a computer listing in terms of the number of 
  1389. usable columns.
  1390.  
  1391. In addition, there are human limitations in the width of the field of view for 
  1392. understanding at the level required for reading source code. These limitations 
  1393. correspond roughly to the 70 to 80 column range.
  1394.  
  1395. automation notes
  1396.  
  1397. The guidelines in this section are easily enforced with an automatic code 
  1398. formatter.
  1399.  
  1400. 2.2     SUMMARY
  1401.  
  1402. code formatting
  1403.  
  1404. o       Use consistent spacing around delimiters.
  1405.  
  1406. o       Use the same spacing as you would in regular prose.
  1407.  
  1408. o       Indent and align nested control structures, continuation lines, and 
  1409. embedded units consistently. 
  1410.  
  1411. o       Distinguish between indentation for nested control structures and for 
  1412. continuation lines.
  1413.  
  1414. o       Use spaces for indentation, not the tab character (Nissen and Wallis 
  1415. 1984, w2.2).
  1416.  
  1417. o       Align operators vertically to emphasize local program structure and 
  1418. semantics.
  1419.  
  1420. o       Use vertical alignment to enhance the readability of declarations.
  1421.  
  1422. o       Provide at most one declaration per line.
  1423.  
  1424. o       Indent all declarations in a single declarative part at the same level.
  1425.  
  1426. o       Align parameter modes and parentheses vertically. 
  1427.  
  1428. o       Use blank lines to group logically related lines of text (NASA 1987).
  1429.  
  1430. o       Highlight the top of each package or task specification, the top of 
  1431. each program unit body, and the end statement of each program unit.
  1432.  
  1433. o       Start each statement on a new line.
  1434.  
  1435. o       Write no more than one simple statement per line.
  1436.  
  1437. o       Break compound statements over multiple lines.
  1438.  
  1439. o       Adhere to a maximum line length limit for source code (Nissen and 
  1440. Wallis 1984, 2.3).
  1441.  
  1442.  
  1443.  
  1444.  
  1445. CHAPTER 3
  1446. Readability
  1447.  
  1448. This chapter recommends ways of using Ada features to make reading and
  1449. understanding code easier. There are many myths about comments and
  1450. readability. The responsibility for true readability rests more with naming
  1451. and code structure than with comments. Having as many comment lines as code
  1452. lines does not imply readability; it more likely indicates the writer does not
  1453. understand what is important to communicate.
  1454.  
  1455. 3.1     SPELLING
  1456.  
  1457. Spelling conventions in source code include rules for capitalization, use of 
  1458. underscores, and use of abbreviations. If these conventions are followed 
  1459. consistently, the resulting code is clearer and more readable.
  1460.  
  1461. 3.1.1   Use of Underscores
  1462.  
  1463. guideline
  1464.  
  1465. o       Use underscores to separate words in a compound name.
  1466.  
  1467. example
  1468.  
  1469. Miles_Per_Hour
  1470. Entry_Value
  1471.  
  1472. rationale
  1473.  
  1474. When an identifier consists of more than one word, it is much easier to read
  1475. if the words are separated by underscores. Indeed, there is precedent in
  1476. English in which compound words are separated by a hyphen. In addition to
  1477. promoting readability of the code, if underscores are used in names, a code
  1478. formatter has more control over altering capitalization. See Guideline .
  1479.  
  1480. 3.1.2   Numbers
  1481.  
  1482. guideline
  1483.  
  1484. o      Represent numbers in a consistent fashion. 
  1485.  
  1486. o       Represent literals in a radix appropriate to the problem.
  1487.  
  1488. o       Use underscores to separate digits the same way commas or periods (or 
  1489. spaces for nondecimal bases) would be used in handwritten text. 
  1490.  
  1491. o    When using scientific notation, make the E consistently either upper
  1492. or lower case.
  1493.  
  1494. o    In an alternate base, represent the alphabetic characters in either
  1495. all upper case or all lower case.
  1496.  
  1497. instantiation
  1498.  
  1499. -       Decimal and octal numbers are grouped by threes beginning counting on 
  1500. either side of the radix point.
  1501.  
  1502. -       The E is always capitalized in scientific notation.
  1503.  
  1504. -       Use upper case for the alphabetic characters representing digits in 
  1505. bases above 10.
  1506.  
  1507. -       Hexadecimal numbers are grouped by fours beginning counting on either 
  1508. side of the radix point.
  1509.  
  1510. example 
  1511.  
  1512. type Maximum_Samples     is range          1 ..  1_000_000;
  1513. type Legal_Hex_Address   is range   16#0000# ..   16#FFFF#;
  1514. type Legal_Octal_Address is range 8#000_000# .. 8#777_777#;
  1515.  
  1516. Avogadro_Number : constant := 6.022_169E+23;
  1517.  
  1518. To represent the number 1/3 as a constant, use
  1519.  
  1520. One_Third : constant := 1.0 / 3.0;
  1521.  
  1522. Avoid this use.
  1523.  
  1524. One_Third_As_Decimal_Approximation : constant := 0.333_333_333_333_33;
  1525.  
  1526. or
  1527.  
  1528. One_Third_Base_3 : constant := 3#0.1#; -- Yes, it really works!
  1529.  
  1530. rationale
  1531.  
  1532. Consistent use of upper case or lower case aids scanning for numbers. 
  1533. Underscores serve to group portions of numbers into familiar patterns. 
  1534. Consistency with common use in everyday contexts is a large part of 
  1535. readability.
  1536.  
  1537. note
  1538.  
  1539. If a rational fraction is represented in a base in which it has a terminating 
  1540. rather than repeating representation, as 3#0.1# does in the example above, it 
  1541. may have increased accuracy upon conversion to the machine base.
  1542.  
  1543. 3.1.3   Capitalization
  1544.  
  1545. guideline
  1546.  
  1547. o    Make reserved words and other elements of the program visually
  1548. distinct from each other.
  1549.  
  1550. instantiation
  1551.  
  1552. -       Use lower case for all reserved words (when used as reserved words).
  1553.  
  1554. -       Use mixed case for all other identifiers, a capital letter beginning 
  1555. every word separated by underscores.
  1556.  
  1557. -       Use upper case for abbreviations and acronyms (see automation note).
  1558.  
  1559. example
  1560.  
  1561. ...
  1562.  
  1563. type Second_Of_Day      is range 0 .. 86_400;
  1564. type Noon_Relative_Time is (Before_Noon, After_Noon, High_Noon);
  1565.  
  1566. subtype Morning   is Second_Of_Day range 0 .. 86_400 / 2 - 1;
  1567. subtype Afternoon is Second_Of_Day range Morning'Last + 2 .. 86_400;
  1568.  
  1569. ...
  1570.  
  1571. Current_Time := Second_Of_Day(Calendar.Seconds(Calendar.Clock));
  1572.  
  1573. if Current_Time in Morning then
  1574.    Time_Of_Day := Before_Noon;
  1575. elsif Current_Time in Afternoon then
  1576.    Time_Of_Day := After_Noon;
  1577. else
  1578.    Time_Of_Day := High_Noon;
  1579. end if;
  1580.  
  1581. case Time_Of_Day is
  1582.    when Before_Noon =>   Get_Ready_For_Lunch;
  1583.    when High_Noon   =>   Eat_Lunch;
  1584.    when After_Noon  =>   Get_To_Work;
  1585. end case;
  1586.  
  1587. ...
  1588.  
  1589. rationale
  1590.  
  1591. Visually distinguishing reserved words allows the reader to focus on program 
  1592. structure alone, if desired, and also aids scanning for particular identifiers.
  1593.  
  1594. The instantiation chosen here is meant to be more readable for the experienced
  1595. Ada programmer, who does not need reserved words to leap off the page.
  1596. Beginners to any language often find that reserved words should be emphasized
  1597. to help them find the control structures more easily.  Because of this,
  1598. instructors in the classroom and books introducing the Ada language may want
  1599. to consider an alternative instantiation.  It should be instructive to note
  1600. that the Ada Language Reference Manual chose to bold all reserved words.
  1601. Upper case for reserved words may also be suitable.
  1602.  
  1603. note
  1604.  
  1605. In Section 2.1, Nissen and Wallis (1984) states that "The choice of case is
  1606. highly debatable, and that chosen for the [Ada Language Reference Manual
  1607. (Department of Defense 1983)] is not necessarily the best. The use of lower
  1608. case for reserved words is often preferred, so that they do not stand out too
  1609. much. However, lower case is generally easier to read than upper case; words
  1610. can be distinguished by their overall shape, and can be found more quickly
  1611. when scanning the text."
  1612.  
  1613. automation note
  1614.  
  1615. Ada names are not case sensitive. Therefore the names max_limit, MAX_LIMIT,
  1616. and Max_Limit denote the same object or entity. A good code formatter should
  1617. be able to automatically convert from one style to another as long as the
  1618. words are delimited by underscores.
  1619.  
  1620. As recommended in Guideline , abbreviations should be project wide.  An
  1621. automated tool should allow a project to specify those abbreviations and
  1622. format them accordingly.
  1623.  
  1624. 3.1.4   Abbreviations
  1625.  
  1626. guideline
  1627.  
  1628. o       Do not use an abbreviation of a long word as an identifier where a 
  1629. shorter synonym exists.
  1630.  
  1631. o       Use a consistent abbreviation strategy.
  1632.  
  1633. o       Do not use ambiguous abbreviations.
  1634.  
  1635. o       An abbreviation must save many characters over the full word to be 
  1636. justified.
  1637.  
  1638. o       Use abbreviations that are well-accepted in the application domain.
  1639.  
  1640. o    Maintain a list of accepted abbreviations and use only abbreviations
  1641. on that list.
  1642.  
  1643. example
  1644.  
  1645. Use Time_Of_Receipt rather than Recd_Time or R_Time.
  1646.  
  1647. But in an application that commonly deals with message formats that meet 
  1648. military standards, DOD_STD_MSG_FMT is an acceptable abbreviation for:
  1649.  
  1650. Department_Of_Defense_Standard_Message_Format.
  1651.  
  1652. rationale
  1653.  
  1654. Many abbreviations are ambiguous or unintelligible unless taken in context. As 
  1655. an example, Temp could indicate either temporary or temperature. For this 
  1656. reason, you should choose abbreviations carefully when you use them.  The 
  1657. rationale in Guideline  provides a more thorough discussion of how context 
  1658. should influence the use of abbreviations.
  1659.  
  1660. Since very long variable names can obscure the structure of the program,
  1661. especially in deeply nested (indented) control structures, it is a good idea
  1662. to try to keep identifiers short and meaningful. Use short unabbreviated names
  1663. whenever possible. If there is no short word which will serve as an
  1664. identifier, then a well known unambiguous abbreviation is the next best
  1665. choice, especially if it comes from a list of standard abbreviations used
  1666. throughout the project.
  1667.  
  1668. An abbreviated format for a fully qualified name can be established via the 
  1669. renames clause. This capability is useful when a very long, fully qualified 
  1670. name would otherwise occur many times in a localized section of code (see 
  1671. Guideline ).
  1672.  
  1673. A list of accepted abbreviations for a project provides a standard context for 
  1674. using each abbreviation. 
  1675.  
  1676. 3.2     NAMING CONVENTIONS
  1677.  
  1678. Choose names that clarify the object's or entity's intended use. Ada allows
  1679. identifiers to be any length as long as the identifier fits on a line with all
  1680. characters being significant (including underscores). Identifiers are the
  1681. names used for variables, constants, program units, and other entities within
  1682. a program.
  1683.  
  1684. 3.2.1   Names
  1685.  
  1686. guideline
  1687.  
  1688. o       Choose names that are as self-documenting as possible.
  1689.  
  1690. o       Use a short synonym instead of an abbreviation (see Guideline 3.1.4).
  1691.  
  1692. o       Use names given by the application but not obscure jargon.
  1693.  
  1694. example
  1695.  
  1696. In a tree-walker, using the name Left instead of Left_Branch is sufficient to
  1697. convey the full meaning given the context.  However, use Time_Of_Day instead
  1698. of TOD.
  1699.  
  1700. Mathematical formulas are often given using single-letter names for variables. 
  1701. Continue this convention for mathematical equations where it would recall the 
  1702. formula; for example:
  1703.  
  1704.    A*(X**2) + B*X + C.
  1705.  
  1706. rationale
  1707.  
  1708. A program that follows these guidelines can be more easily comprehended.  
  1709. Self-documenting names require fewer explanatory comments. Empirical studies 
  1710. have shown that you can further improve comprehension if your variable names 
  1711. are not excessively long (Schneiderman 1986, 7). The context and application 
  1712. can help greatly. The unit of measure for numeric entities can be a source of 
  1713. type names.
  1714.  
  1715. note
  1716.  
  1717. See Guideline  for a discussion on how to use the application domain as a 
  1718. guideline for selecting abbreviations.
  1719.  
  1720. 3.2.2   Type Names
  1721.  
  1722. guideline
  1723.  
  1724. o       Use singular, general nouns as (sub)type identifiers.
  1725.  
  1726. o       Choose identifiers that describe one of the (sub)type's values.
  1727.  
  1728. o    Do not use identifier constructions (e.g., suffixes) that are unique
  1729. to (sub)type identifiers.
  1730.  
  1731. o       Do not use the type names from predefined packages.
  1732.  
  1733. example
  1734.  
  1735. type Day is
  1736.    (Monday,    Tuesday,   Wednesday, Thursday,  Friday,
  1737.     Saturday,  Sunday);
  1738.  
  1739. type Day_Of_Month    is range      0 ..    31;
  1740. type Month_Number    is range      1 ..    12;
  1741. type Historical_Year is range -6_000 .. 2_500;
  1742.  
  1743. type Date is
  1744.    record
  1745.       Day   : Day_Of_Month;
  1746.       Month : Month_Number;
  1747.       Year  : Historical_Year;
  1748.    end record;
  1749.  
  1750. In particular, Day should be used in preference to Days or Day_Type;
  1751.  
  1752. The identifier Historical_Year might appear to be specific, but it is actually 
  1753. general, with the adjective, historical, describing the range constraint.
  1754.  
  1755. rationale
  1756.  
  1757. When this style and the suggested style for object identifiers are used, 
  1758. program code more closely resembles English (see Guideline 3.2.3).  
  1759. Furthermore, this style is consistent with the names of the language's 
  1760. predefined identifiers.  They are not named Integers, Booleans, Integer_Type, 
  1761. or Boolean_Type.
  1762.  
  1763. However, using the name of a type from the predefined packages is sure to 
  1764. confuse a programmer when that type appears somewhere without a package 
  1765. qualification.
  1766.  
  1767. 3.2.4   Object Names
  1768.  
  1769. guideline
  1770.  
  1771. o       Use predicate clauses or adjectives for boolean objects.
  1772.  
  1773. o       Use singular, specific nouns as object identifiers.
  1774.  
  1775. o       Choose identifiers that describe the object's value during execution.
  1776.  
  1777. o       Use singular, general nouns as identifiers for record components.
  1778.  
  1779. example
  1780.  
  1781. Nonboolean objects:
  1782.  
  1783. Today           : Day;
  1784. Yesterday       : Day;
  1785. Retirement_Date : Date;
  1786.  
  1787. Boolean objects:
  1788.  
  1789. User_Is_Available : Boolean;        -- predicate clause
  1790. List_Is_Empty     : Boolean;        -- predicate clause
  1791. Empty             : Boolean;        -- adjective
  1792. Bright            : Boolean;        -- adjective
  1793.  
  1794. rationale
  1795.  
  1796. Using specific nouns for objects establishes a context for understanding the
  1797. object's value, which is one of the general values described by the
  1798. (sub)type's name (Guideline 3.2.2).  Object declarations become very
  1799. English-like with this style.  For example, the first declaration above is
  1800. read as "Today is a Day."
  1801.  
  1802. General nouns, rather that specific, are used for record components because a 
  1803. record object's name will supply the context for understanding the component.  
  1804. Thus, the following component is understood as "the year of retirement.":
  1805.  
  1806. Retirement_Date.Year
  1807.  
  1808. Following conventions which relate object types and parts of speech makes code 
  1809. read more like text. For example, because of the names chosen, the following 
  1810. code segment needs no comments:
  1811.  
  1812. if List_Is_Empty then
  1813.    Number_Of_Elements := 0;
  1814. else
  1815.    Number_Of_Elements := Length_Of_List;
  1816. end if;
  1817.  
  1818. note
  1819.  
  1820. If it is difficult to find a specific noun that describes an object's value 
  1821. during the entire execution of a program, the object is probably serving 
  1822. multiple purposes.  Multiple objects should be used in such a case.
  1823.  
  1824. 3.2.4   Program Unit Names
  1825.  
  1826. guideline
  1827.  
  1828. o       Use action verbs for procedures and entries.
  1829.  
  1830. o       Use predicate-clauses for boolean functions.
  1831.  
  1832. o       Use nouns for nonboolean functions.
  1833.  
  1834. o       Give packages names that imply higher levels of organization than 
  1835. subprograms. Generally, these are noun phrases that describe the abstraction 
  1836. provided. 
  1837.  
  1838. o       Give tasks names that imply an active entity.  
  1839.  
  1840. o       Name generic subprograms as if they were nongeneric subprograms.
  1841.  
  1842. o       Name generic packages as if they were nongeneric packages.
  1843.  
  1844. o       Make the generic names more general than the instantiated names.
  1845.  
  1846. example
  1847.  
  1848. The following are sample names for elements that comprise an Ada program.
  1849.  
  1850. Sample procedure names:
  1851.  
  1852. procedure Get_Next_Token          -- get is a transitive verb
  1853. procedure Create                  -- create is a transitive verb
  1854.  
  1855. Sample function names for boolean-valued functions:
  1856.  
  1857. function Is_Last_Item             -- predicate clause
  1858. function Is_Empty                 -- predicate clause
  1859.  
  1860. Sample function names for nonboolean-valued functions:
  1861.  
  1862. function Successor                -- common noun
  1863. function Length                   -- attribute
  1864. function Top                      -- component
  1865.  
  1866. Sample package names:
  1867.  
  1868. package Terminal is               -- common noun
  1869. package Text_Utilities is         -- common noun
  1870.  
  1871. Sample task names:
  1872.  
  1873. task Terminal_Resource_Manager is -- common noun that shows action
  1874.  
  1875. Below is a sample piece of code to show the clarity that results from using 
  1876. these conventions the parts-of-speech naming conventions.
  1877.   
  1878.  
  1879. Get_Next_Token(Current_Token);
  1880.  
  1881. case Current_Token is
  1882.    when Identifier =>         Process_Identifier;
  1883.    when Numeric    =>         Process_Numeric;
  1884. end case;  -- Current_Token
  1885.  
  1886. if Is_Empty(Current_List) then
  1887.    Number_Of_Elements := 0;
  1888. else
  1889.    Number_Of_Elements := Length(Current_List);
  1890. end if;
  1891.  
  1892. When packages and their subprograms are named together, the resulting code is 
  1893. very descriptive.
  1894.  
  1895. if Stack.Is_Empty(Current_List) then
  1896.    Current_Token := Stack.Top(Current_List);
  1897. end if;
  1898.  
  1899. rationale
  1900.  
  1901. Using these naming conventions creates understandable code that reads much
  1902. like natural language. When verbs are used for actions, such as subprograms,
  1903. and nouns are used for objects, such as the data that the subprogram
  1904. manipulates, code is easier to read and understand. This models a medium of
  1905. communication already familiar to a reader. Where the pieces of a program
  1906. model a real-life situation, using these conventions reduces the number of
  1907. translation steps involved in reading and understanding the program. In a
  1908. sense, your choice of names reflects the level of abstraction from computer
  1909. hardware toward application requirements.
  1910.  
  1911. note
  1912.  
  1913. There are some conflicting conventions in current use for task entries. Some 
  1914. programmers and designers advocate naming task entries with the same 
  1915. conventions used for subprograms to blur the fact that a task is involved. 
  1916. Their reasoning is that if the task is reimplemented as a package, or vice 
  1917. versa, the names need not change. Others prefer to make the fact of a task 
  1918. entry as explicit as possible to ensure that the existence of a task with its 
  1919. presumed overhead is recognizable. Project-specific priorities may be useful in
  1920. choosing between these conventions.
  1921.  
  1922. 3.2.5   Constants and Named Numbers
  1923.  
  1924. guideline
  1925.  
  1926. o       Use symbolic values instead of literals wherever possible.
  1927.  
  1928. o       Use constants instead of variables for constant values.
  1929.  
  1930. o       Use named numbers instead of constants when possible.
  1931.  
  1932. o       Use named numbers to replace numeric literals whose type or context is 
  1933. truly universal.
  1934.  
  1935. o       Use constants for objects whose values cannot change after elaboration 
  1936. (United Technologies 1987).
  1937.  
  1938. o    Show relationships between symbolic values by defining them with
  1939. static expressions.
  1940.  
  1941. o       Use linearly independent sets of literals.
  1942.  
  1943. o       Use attributes like 'First and 'Last instead of literals wherever 
  1944. possible.
  1945.  
  1946. example
  1947.  
  1948. 3.141_592_653_589_793                 -- literal
  1949. Max : constant Integer := 65_535;     -- constant
  1950. Pi  : constant         := 3.141_592;  -- named number
  1951. PI / 2                                -- static expression
  1952. PI                                    -- symbolic value
  1953.  
  1954. Declaring Pi as a named number allows it to be referenced symbolically in the 
  1955. assignment statement below:
  1956.  
  1957. Area :=       Pi * Radius**2;       -- if radius is known.
  1958.  
  1959. instead of
  1960.  
  1961. Area := 3.141_59 * Radius**2;       -- Needs explanatory comment.
  1962.  
  1963. Also, ASCII.Bel is more expressive than Character'Val(8#007#).
  1964.  
  1965. Clarity of constant and named number declarations can be improved by using 
  1966. other constant and named numbers. For example:
  1967.  
  1968. Bytes_Per_Page   : constant := 512;
  1969. Pages_Per_Buffer : constant := 10;
  1970. Buffer_Size      : constant := Pages_Per_Buffer * Bytes_Per_Page;
  1971.  
  1972. is more self-explanatory and easier to maintain than
  1973.  
  1974. Buffer_Size : constant := 5_120;   -- ten pages
  1975.  
  1976. The following literals should be constants:
  1977.  
  1978. if New_Character  = '$' then  -- "constant" that may change
  1979. ...
  1980. if Current_Column = 7 then    -- "constant" that may change
  1981.  
  1982. rationale
  1983.  
  1984. Using identifiers instead of literals makes the purpose of expressions clear
  1985. reducing the need for comments. Constant declarations consisting of
  1986. expressions of numeric literals are safer since they do not need to be
  1987. computed by hand.  They are also more enlightening than a single numeric
  1988. literal since there is more opportunity for embedding explanatory names.
  1989. Clarity of constant declarations can be improved further by using other
  1990. related constants in static expressions defining new constants. This is not
  1991. less efficient because static expressions of named numbers are computed at
  1992. compile time.
  1993.  
  1994. A constant has a type. A named number can only be a universal type: universal
  1995. integer or universal real. Strong typing is enforced for identifiers but not
  1996. literals. Named numbers allow compilers to generate more efficient code than
  1997. for constants and to perform more complete error checking at compile time. If
  1998. the literal contains a large number of digits (as Pi in the example above),
  1999. the use of an identifier reduces keystroke errors. If keystroke errors occur,
  2000. they are easier to locate either by inspection or at compile time.
  2001.  
  2002. Linear independence of literals means that the few literals that are used do 
  2003. not depend on one another and that any relationship between constant or named 
  2004. values is shown in the static expressions. Linear independence of literal 
  2005. values gives the property that if one literal value changes, all of the named 
  2006. numbers of values dependent on that literal are automatically changed.
  2007.  
  2008. note
  2009.  
  2010. There are some gray areas where the literal is actually more self-documenting
  2011. than a name. These are application-specific and generally occur with
  2012. universally familiar, unchangeable values such as the following relationship: 
  2013.  
  2014. Fahrenheit := 32.0 + (9.0 * Celsius) / 5.0;
  2015.  
  2016. 3.3     COMMENTS
  2017.  
  2018. Ada comments can be either beneficial or harmful to software maintainers. They
  2019. can be beneficial by explaining aspects of the code that are otherwise not
  2020. readily apparent. They can be harmful by containing inaccurate information and
  2021. by being too numerous and not visually distinct enough, which can cause them
  2022. to obscure the structure of the code.
  2023.  
  2024. Comments should be minimized. They should provide needed information that 
  2025. cannot be expressed in the Ada language, emphasize the structure of code, and 
  2026. draw attention to deliberate and necessary violations of the guidelines. 
  2027. Comments are present either to draw attention to the real issue being 
  2028. exemplified or to compensate for incompleteness in the example program.
  2029.  
  2030. Maintenance programmers need to know the causal interaction of noncontiguous
  2031. pieces of code to get a global, more or less complete sense of the program.
  2032. They typically acquire this kind of information from mental simulation of
  2033. parts of the code. Comments should be sufficient enough to support this
  2034. process (Soloway et al. 1986).
  2035.  
  2036. This section presents general guidelines about how to write good comments.  It 
  2037. then defines several different classes of comments with guidelines for the use 
  2038. of each. The classes are: file headers, program unit specification headers, 
  2039. program unit body headers, data comments, statement comments, and marker 
  2040. comments.
  2041.  
  2042. 3.3.1   General Comments
  2043.  
  2044. guideline
  2045.  
  2046. o       Make the code as clear as possible to reduce the need for comments.
  2047.  
  2048. o    Never repeat information in a comment which is readily available in
  2049. the code.
  2050.  
  2051. o       Where a comment is required, make it concise and complete.
  2052.  
  2053. o       Use proper grammar and spelling in comments.
  2054.  
  2055. o       Make comments visually distinct from the code.
  2056.  
  2057. o       Structure comments in headers so that information can be automatically 
  2058. extracted by a tool.
  2059.  
  2060. rationale
  2061.  
  2062. The structure and function of well written code is clear without comments.
  2063. Obscure or badly structured code is hard to understand, maintain, or reuse
  2064. regardless of comments. Bad code should be improved, not explained. Reading
  2065. the code itself is the only way to be absolutely positive about what the code
  2066. does.  Therefore, the code should be made as readable as possible.
  2067.  
  2068. Using comments to duplicate information in the code is a bad idea for several
  2069. reasons. First, it is unnecessary work that decreases productivity. Second, it
  2070. is very difficult to correctly maintain the duplication as the code is
  2071. modified. When changes are made to existing code, it is compiled and tested to
  2072. make sure that it is once again correct. However, there is no automatic
  2073. mechanism to make sure that the comments are correctly updated to reflect the
  2074. changes. Very often, the duplicate information in a comment becomes obsolete
  2075. at the first code change and remains so through the life of the software.
  2076. Third, when comments about an entire system are written from the limited point
  2077. of view of the author of a single subsystem, the comments are often incorrect
  2078. from the start.
  2079.  
  2080. Comments are necessary to reveal information difficult or impossible to obtain 
  2081. from the code. Subsequent sections of this book contain examples of such 
  2082. comments. Completely and concisely present the required information.
  2083.  
  2084. The purpose of comments is to help readers understand the code. Misspelled, 
  2085. ungrammatical, ambiguous, or incomplete comments defeat this purpose. If a 
  2086. comment is worth adding, it is worth adding correctly in order to increase its 
  2087. usefulness.
  2088.  
  2089. Making comments visually distinct from the code, by indenting them, grouping 
  2090. them together into headers, or highlighting them with dashed lines is useful 
  2091. because it makes the code easier to read. Subsequent sections of this book 
  2092. elaborate on this point.
  2093.  
  2094. automation note
  2095.  
  2096. The guideline about storing redundant information in comments applies only to
  2097. manually generated comments. There are tools which automatically maintain
  2098. information about the code (e.g., calling units, called units, cross-reference
  2099. information, revision histories, etc.), storing it in comments in the same
  2100. file as the code. Other tools read comments, but do not update them, using the
  2101. information from the comments to automatically generate detailed design
  2102. documents and other reports.
  2103.  
  2104. The use of such tools is encouraged, and may require that you structure your
  2105. header comments so they can be automatically extracted and/or updated. Beware
  2106. that tools which modify the comments in a file are only useful if they are
  2107. executed frequently enough. Automatically generated obsolete information is
  2108. even more dangerous than manually generated obsolete information, because it
  2109. is more trusted by the reader.
  2110.  
  2111. Revision histories are maintained much more accurately and completely by
  2112. configuration management tools. With no tool support, it is very common for an
  2113. engineer to make a change and forget to update the revision history. If your
  2114. configuration management tool is capable of maintaining revision histories as
  2115. comments in the source file, then take advantage of that capability,
  2116. regardless of any compromise you might have to make about the format or
  2117. location of the revision history. It is better to have a complete revision
  2118. history appended to the end of the file than to have a partial one formatted
  2119. nicely and embedded in the file header.
  2120.  
  2121. 3.3.2   File Headers
  2122.  
  2123. guideline
  2124.  
  2125. o       Put a file header on each source file.
  2126.  
  2127. o       Place ownership, responsibility, and history information for the file 
  2128. in the file header.
  2129.  
  2130. instantiation
  2131.  
  2132. -       Put a copyright notice in the file header.
  2133.  
  2134. -       Put the author's name and department in the file header.
  2135.  
  2136. -       Put a revision history in the file header, including a summary of each 
  2137. change, the date, and the name of the person making the change.
  2138.  
  2139. example
  2140.  
  2141. ------------------------------------------------------------------------
  2142. --      Copyright (c) 1991, Software Productivity Consortium, Inc.
  2143. --      All rights reserved.
  2144.  
  2145. -- Author: J. Smith
  2146.  
  2147. -- Department:System Software Department
  2148.  
  2149. -- Revision History:
  2150. --   7/9/91 J. Smith
  2151. --     - Added function Size_Of to support queries of node sizes.
  2152. --     - Fixed bug in Set_Size which caused overlap of large nodes.
  2153. --   7/1/91 M. Jones
  2154. --     - Optimized clipping algorithm for speed.
  2155. --   6/25/91 J. Smith
  2156. --     - Original version.
  2157. ------------------------------------------------------------------------
  2158.  
  2159. rationale
  2160.  
  2161. Ownership information should be present in each file if you want to be sure to 
  2162. protect your rights to the software. Furthermore, for high visibility, it 
  2163. should be the very first thing in the file.
  2164.  
  2165. Responsibility and revision history information should be present in each file
  2166. for the sake of future maintainers, this is the header information most
  2167. trusted by maintainers because it accumulates. It does not evolve. There is no
  2168. need to ever go back and modify the author's name or the revision history of a
  2169. file. As the code evolves, the revision history should be updated to reflect
  2170. each change. At worst, it will be incomplete, it should rarely be wrong. Also,
  2171. the number and frequency of changes and the number of different people who
  2172. made the changes over the history of a unit can be good indicators of the
  2173. integrity of the implementation with respect to the design.
  2174.  
  2175. Information about how to find the original author should be included in the
  2176. file header, in addition to the author's name, to make it easier for
  2177. maintainers to find the author in case questions arise. However, detailed
  2178. information like phone numbers, mail stops, office numbers, and computer
  2179. account usernames are too volatile to be very useful. It is better to record
  2180. the department for which the author was working when the code was written.
  2181. This information is still useful if the author moves offices, changes
  2182. departments, or even leaves the company, because the department is likely to
  2183. retain responsibility for the original version of the code.
  2184.  
  2185. 3.3.3   Program Unit Specification Header
  2186.  
  2187. guideline
  2188.  
  2189. o       Put a header on the specification of each program unit.
  2190.  
  2191. o       Place information required by the user of the program unit in the 
  2192. specification header.
  2193.  
  2194. o       Do not repeat information (except unit name) in the specification 
  2195. header which is present in the specification.
  2196.  
  2197. o       Explain what the unit does, not how or why it does it.
  2198.  
  2199. o       Describe the complete interface to the program unit, including any 
  2200. exceptions it can raise and any global effects it can have.
  2201.  
  2202. o       Do not include information about how the unit fits into the enclosing 
  2203. software system.
  2204.  
  2205. o       Describe the performance (time and space) characteristics of the unit.
  2206.  
  2207. instantiation
  2208.  
  2209. -       Put the name of the program unit in the header.
  2210.  
  2211. -       Briefly explain the purpose of the program unit.
  2212.  
  2213. -       For packages, describe the effects of the visible subprograms on each 
  2214. other, and how they should be used together.
  2215.  
  2216. -       List all exceptions which can be raised by the unit.
  2217.  
  2218. -       List all global effects of the unit.
  2219.  
  2220. -       List preconditions and postconditions of the unit.
  2221.  
  2222. -       List hidden tasks activated by the unit.
  2223.  
  2224. -       Do not list the names of parameters of a subprogram.
  2225.  
  2226. -       Do not list the names of package subprograms just to list them.
  2227.  
  2228. -       Do not list the names of all other units used by the unit.
  2229.  
  2230. -       Do not list the names of all other units which use the unit.
  2231.  
  2232. example
  2233.  
  2234. ------------------------------------------------------------------------
  2235. -- AUTOLAYOUT
  2236.  
  2237. -- Purpose:
  2238. --   This package computes positional information for nodes and arcs
  2239. --   of a directed graph.  It encapsulates a layout algorithm which is
  2240. --   designed to minimize the number of crossing arcs and to emphasize
  2241. --   the primary direction of arc flow through the graph.
  2242.  
  2243. -- Effects:
  2244. --   - The expected usage is:
  2245. --     1. Call Define for each node and arc to define the graph.
  2246. --     2. Call Layout to assign positions to all nodes and arcs.
  2247. --     3. Call Position_Of for each node and arc to determine the
  2248. --        assigned coordinate positions.
  2249. --   - Layout can be called multiple times, and recomputes the
  2250. --     positions of all currently defined nodes and arcs each time.
  2251. --   - Once a node or arc has been defined, it remains defined until
  2252. --     Clear is called to delete all nodes and arcs.
  2253.  
  2254. -- Performance:
  2255. --   This package has been optimized for time, in preference to space.
  2256. --   Layout times are on the order of N*log(N) where N is the number
  2257. --   of nodes, but memory space is used inefficiently.
  2258. ------------------------------------------------------------------------
  2259.  
  2260. package Autolayout is
  2261.  
  2262.    ...
  2263.  
  2264.    ---------------------------------------------------------------------
  2265.    -- Define
  2266.  
  2267.    -- Purpose:
  2268.    --   This procedure defines one node of the current graph.
  2269.    -- Exceptions:
  2270.    --   Node_Already_Defined
  2271.    ---------------------------------------------------------------------
  2272.    procedure Define
  2273.      (New_Node : in     Node);
  2274.  
  2275.    ---------------------------------------------------------------------
  2276.    -- Layout
  2277.  
  2278.    -- Purpose:
  2279.    --   This procedure assigns coordinate positions to all defined
  2280.    --   nodes and arcs.
  2281.    -- Exceptions:
  2282.    --   None.
  2283.    ---------------------------------------------------------------------
  2284.    procedure Layout;
  2285.  
  2286.    ---------------------------------------------------------------------
  2287.    -- Position_Of
  2288.  
  2289.    -- Purpose:
  2290.    --   This function returns the coordinate position of the
  2291.    --   specified node.  The default position (0,0) is returned if no
  2292.    --   position has been assigned yet.
  2293.    -- Exceptions:
  2294.    --   Node_Not_Defined
  2295.    ---------------------------------------------------------------------
  2296.    function Position_Of (Current : in     Node)
  2297.      return Position;
  2298.  
  2299.    ...
  2300.  
  2301. end Autolayout;
  2302.  
  2303. rationale
  2304.  
  2305. The purpose of a header comment on the specification of a program unit is to
  2306. help the user understand how to use the program unit. From reading the program
  2307. unit specification and header, a user should know everything necessary to use
  2308. the unit. It should not be necessary to read the body of the program unit.
  2309. Therefore, there should be a header comment on each program unit
  2310. specification, and each header should contain all usage information not
  2311. expressed in the specification itself. Such information includes the units'
  2312. effect on each other and on shared resources, exceptions raised, and
  2313. time/space characteristics.  None of this information can be determined from
  2314. the Ada specification of the program unit.
  2315.  
  2316. When you duplicate information in the header that can be readily obtained from 
  2317. the specification, the information tends to become incorrect during 
  2318. maintenance. For example, do not make a point of listing all parameter names, 
  2319. modes, or types when describing a procedure. This information is already 
  2320. available from the procedure specification. Similarly, do not list all 
  2321. subprograms of a package in the header unless this is necessary to make some 
  2322. important statement about the subprograms.
  2323.  
  2324. Do not include information in the header which the user of the program unit 
  2325. doesn't need. In particular, do not include information about how a program 
  2326. unit performs its function or why a particular algorithm was used. This 
  2327. information should be hidden in the body of the program unit to preserve the 
  2328. abstraction defined by the unit. If the user knows such details and makes 
  2329. decisions based on that information, the code may suffer when that information 
  2330. is later changed.
  2331.  
  2332. When describing the purpose of the unit, avoid referring to other parts of the
  2333. enclosing software system. It is better to say "this unit does ..." than to
  2334. say "this unit is called by Xyz to do ...." The unit should be written in such
  2335. a way that it does not know or care which unit is calling it. This makes the
  2336. unit much more general purpose and reusable. In addition, information about
  2337. other units is likely to become obsolete and incorrect during maintenance.
  2338.  
  2339. Include information about the performance (time and space) characteristics of
  2340. the unit. Much of this information is not present in the Ada specification,
  2341. but it is required by the user. To integrate the unit into a system, the user
  2342. needs to understand the resource usage (CPU, memory, etc.) of the unit. It is
  2343. especially important to note when a subprogram call causes activation of a
  2344. task hidden in a package body, the task may continue to consume resources
  2345. after the subroutine ends.
  2346.  
  2347. exception
  2348.  
  2349. Where a group of program units are closely related or simple to understand, it
  2350. is acceptable to use a single header for the entire group of program units.
  2351. For example, it makes sense to use a single header to describe the behavior of
  2352. Max and Min functions; Sin, Cos, and Tan functions; or a group of functions to
  2353. query related attributes of an object encapsulated in a package. This is
  2354. especially true when each function in the set is capable of raising the same
  2355. exceptions.
  2356.  
  2357. 3.3.4   Program Unit Body Header
  2358.  
  2359. guideline
  2360.  
  2361. o    Place information required by the maintainer of the program unit in
  2362. the body header.
  2363.  
  2364. o       Explain how and why the unit performs its function, not what the unit 
  2365. does.
  2366.  
  2367. o       Do not repeat information (except unit name) in the header that is 
  2368. readily apparent from reading the code.
  2369.  
  2370. o     Do not repeat information (except unit name) in the body header that
  2371. is available in the specification header.
  2372.  
  2373. instantiation
  2374.  
  2375. -       Put the name of the program unit in the header.
  2376.  
  2377. -       Record portability issues in the header.
  2378.  
  2379. -       Summarize complex algorithms in the header.
  2380.  
  2381. -       Record reasons for significant or controversial implementation 
  2382. decisions.
  2383.  
  2384. -     Record discarded implementation alternatives, along with the reason
  2385. for discarding them.
  2386.  
  2387. -       Record anticipated changes in the header, especially if some work has 
  2388. already been done to the code to make the changes easy to accomplish.
  2389.  
  2390. example
  2391.  
  2392. ------------------------------------------------------------------------
  2393. -- Autolayout
  2394.  
  2395. -- Implementation Notes:
  2396. --   - This package uses a heuristic algorithm to minimize the number
  2397. --     of arc crossings.  It does not always achieve the true minimum
  2398. --     number which could theoretically be reached.  However it does a
  2399. --     nearly perfect job in relatively little time.  For details about
  2400. --     the algorithm, see ...
  2401.  
  2402. -- Portability Issues:
  2403. --   - The native math package Math_Lib is used for computations of
  2404. --     coordinate positions.
  2405. --   - 32-bit integers are required.
  2406. --   - No operating system specific routines are called.
  2407.  
  2408. -- Anticipated Changes:
  2409. --   - Coordinate_Type below could be changed from integer to float
  2410. --     with little effort.  Care has been taken to not depend on the
  2411. --     specific characteristics of integer arithmetic.
  2412. ------------------------------------------------------------------------
  2413. package body Autolayout is
  2414.  
  2415.    ...
  2416.  
  2417.    ---------------------------------------------------------------------
  2418.    -- Define
  2419.  
  2420.    -- Implementation Notes:
  2421.    --   - This routine stores a node in the general purpose Graph data
  2422.    --     structure, not the Fast_Graph structure because ...
  2423.    ---------------------------------------------------------------------
  2424.    procedure Define
  2425.      (New_Node : in     Node) is
  2426.    begin
  2427.       ...
  2428.    end Define;
  2429.  
  2430.    ---------------------------------------------------------------------
  2431.    -- Layout
  2432.  
  2433.    -- Implementation Notes:
  2434.    --   - This routine copies the Graph data structure (optimized for
  2435.    --     fast random access) into the Fast_Graph data structure
  2436.    --     (optimized for fast sequential iteration), then performs the
  2437.    --     layout, and copies the data back to the Graph structure.  This
  2438.    --     technique was introduced as an optimization when the algorithm
  2439.    --     was found to be too slow, and it produced an order of
  2440.    --     magnitude improvement.
  2441.    ---------------------------------------------------------------------
  2442.    procedure Layout is
  2443.    begin
  2444.       ...
  2445.    end Layout;
  2446.  
  2447.    ---------------------------------------------------------------------
  2448.    -- Position_Of
  2449.    ---------------------------------------------------------------------
  2450.    function Position_Of (Current : in     Node)
  2451.      return Position is
  2452.    begin
  2453.  
  2454.       ...
  2455.    end Position_Of;
  2456.  
  2457.    ...
  2458.  
  2459. end Autolayout;
  2460.  
  2461. rationale
  2462.  
  2463. The purpose of a header comment on the body of a program unit is to help the 
  2464. maintainer of the program unit to understand the implementation of the unit, 
  2465. including tradeoffs among different techniques. Be sure to document all 
  2466. decisions made during implementation to prevent the maintainer from making the 
  2467. same mistakes you made. One of the most valuable comments to a maintainer is a 
  2468. clear description of why a change being considered will not work.
  2469.  
  2470. The header is also a good place to record portability concerns. The maintainer 
  2471. may have to port the software to a different environment and will benefit from 
  2472. a list of nonportable features.  Furthermore, the act of collecting and 
  2473. recording portability issues focuses attention on these issues and may result 
  2474. in more portable code from the start.
  2475.  
  2476. Summarize complex algorithms in the header if the code is difficult to read or 
  2477. understand without such a summary, but do not merely paraphrase the code. Such 
  2478. duplication is unnecessary and hard to maintain. Similarly, do not repeat the 
  2479. information from the header of the program unit specification.
  2480.  
  2481. note
  2482.  
  2483. It is often the case that a program unit is self-explanatory enough that it
  2484. requires no body header to explain how it is implemented or why. In such a
  2485. case, omit the header entirely, as in the case with Position_Of above. Be
  2486. sure, however, that the header you omit truly contains no information. For
  2487. example, consider the difference between the two header sections:
  2488.  
  2489. -- Implementation Notes:  None.
  2490.  
  2491. and
  2492.  
  2493. -- NonPortable Features:  None.
  2494.  
  2495. The first is a message from the author to the maintainer saying "I can't think
  2496. of anything else to tell you," while the second may mean "I guarantee that this
  2497. unit is entirely portable."
  2498.  
  2499. 3.3.5   Data Comments
  2500.  
  2501. guideline
  2502.  
  2503. o       Comment on all data types, objects, and exceptions unless their names 
  2504. are self-explanatory.
  2505.  
  2506. o       Include information on the semantic structure of complex pointer-based
  2507. data structures.
  2508.  
  2509. o       Include information about relationships that are maintained between 
  2510. data objects.
  2511.  
  2512. o       Do not include comments that merely repeat the information in the name.
  2513.  
  2514. example
  2515.  
  2516. Objects can be grouped by purpose and commented as:
  2517.  
  2518. ...
  2519.  
  2520. ---------------------------------------------------------------------
  2521. -- Current position of the cursor in the currently selected text
  2522. -- buffer, and the most recent position explicitly marked by the
  2523. -- user.
  2524.  
  2525. -- Note:  It is necessary to maintain both current and desired
  2526. --        column positions because the cursor cannot always be
  2527. --        displayed in the desired position when moving between
  2528. --        lines of different lengths.
  2529. ---------------------------------------------------------------------
  2530.  
  2531. Desired_Column : Column_Counter;
  2532. Current_Column : Column_Counter;
  2533. Current_Row    : Row_Counter;
  2534. Marked_Column  : Column_Counter;
  2535. Marked_Row     : Row_Counter;
  2536.  
  2537. The conditions under which an exception is raised should be commented:
  2538.  
  2539. ---------------------------------------------------------------------
  2540. -- Exceptions
  2541. ---------------------------------------------------------------------
  2542. Node_Already_Defined : exception;   -- Raised when an attempt is made
  2543.                     --|   to define a node with an
  2544.                     --|   identifier which already
  2545.                     --|   defines a node.
  2546. Node_Not_Defined     : exception;   -- Raised when a reference is
  2547.                     --|   made to a node which has
  2548.                     --|   not been defined.
  2549.  
  2550. Here is a more complex example, involving multiple record and access types 
  2551. which are used to form a complex data structure:
  2552.  
  2553. ---------------------------------------------------------------------
  2554. -- These data structures are used to store the graph during the
  2555. -- layout process. The overall organization is a sorted list of
  2556. -- "ranks," each containing a sorted list of nodes, each containing
  2557. -- a list of incoming arcs and a list of outgoing arcs.
  2558.  
  2559. -- The lists are doubly linked to support forward and backward
  2560. -- passes for sorting. Arc lists do not need to be doubly linked
  2561. -- because order of arcs is irrelevant.
  2562.  
  2563. -- The nodes and arcs are doubly linked to each other to support
  2564. -- efficient lookup of all arcs to/from a node, as well as efficient
  2565. -- lookup of the source/target node of an arc.
  2566. ---------------------------------------------------------------------
  2567.  
  2568. type Arc;
  2569. type Arc_Pointer is access Arc;
  2570.  
  2571. type Node;
  2572. type Node_Pointer is access Node;
  2573.  
  2574. type Node is
  2575.    record
  2576.       Id       : Node_Pointer;-- Unique node ID supplied by the user.
  2577.       Arc_In   : Arc_Pointer;
  2578.       Arc_Out  : Arc_Pointer;
  2579.       Next     : Node_Pointer;
  2580.       Previous : Node_Pointer;
  2581.    end record;
  2582.  
  2583. type Arc is
  2584.    record
  2585.       ID     : Arc_ID;        -- Unique arc ID supplied by the user.
  2586.       Source : Node_Pointer;
  2587.       Target : Node_Pointer;
  2588.       Next   : Arc_Pointer;
  2589.    end record;
  2590.  
  2591. type Rank;
  2592. type Rank_Pointer is access Rank;
  2593.  
  2594. type Rank is
  2595.    record
  2596.       Number     : Level_ID;  -- Computed ordinal number of the rank.
  2597.       First_Node : Node_Pointer;
  2598.       Last_Node  : Node_Pointer;
  2599.       Next       : Rank_Pointer;
  2600.       Previous   : Rank_Pointer;
  2601.    end record;
  2602.  
  2603. First_Rank : Rank_Pointer;
  2604. Last_Rank  : Rank_Pointer;
  2605.  
  2606. rationale
  2607.  
  2608. It is very useful to add comments explaining the purpose, structure, and
  2609. semantics of the data structures. Many maintainers look at the data structures
  2610. first when trying to understand the implementation of a unit. Understanding
  2611. the data which can be stored, along with the relationships between the
  2612. different data items, and the flow of data through the unit is an important
  2613. first step in understanding the details of the unit.
  2614.  
  2615. In the first example above, the names Current_Column and Current_Row are 
  2616. relatively self-explanatory. The name Desired_Column is also well chosen, but
  2617. it leaves the reader wondering what the relationship is between the current 
  2618. column and the desired column. The comment explains the reason for having both.
  2619.  
  2620. Another advantage of commenting on the data declarations is that the single
  2621. set of comments on a declaration can replace multiple sets of comments that
  2622. might otherwise be needed at various places in the code where the data is
  2623. manipulated. In the first example above, the comment briefly expands on the
  2624. meaning of "current" and "marked." It states that the "current" position is
  2625. the location of the cursor, the "current" position is in the current buffer,
  2626. and the "marked" position was marked by the user. This comment, along with the
  2627. mnemonic names of the variables, greatly reduces the need for comments at
  2628. individual statements throughout the code.
  2629.  
  2630. It is important to document the full meaning of exceptions and under what
  2631. conditions they can be raised, as shown in the second example above,
  2632. especially when the exceptions are declared in a package specification. The
  2633. reader has no other way to find out the exact meaning of the exception
  2634. (without reading the code in the package body).
  2635.  
  2636. Grouping all the exceptions together, as shown in the second example, can 
  2637. provide the reader with the effect of a "glossary" of special conditions. This
  2638. is useful when many different subprograms in the package can raise the same 
  2639. exceptions. For a package in which each exception can be raised by only one 
  2640. subprogram, it may be better to group related subprograms and exceptions 
  2641. together.
  2642.  
  2643. When commenting exceptions, it is better to describe the exception's meaning
  2644. in general terms than to list all the subprograms that can cause the exception
  2645. to be raised; such a list is harder to maintain. When a new routine is added,
  2646. it is likely that these lists will not be updated. Also, this information is
  2647. already present in the comments describing the subprograms, where all
  2648. exceptions that can be raised by the subprogram should be listed. Lists of
  2649. exceptions by subprogram are more useful and easier to maintain than lists of
  2650. subprograms by exception.
  2651.  
  2652. In the third example, the names of the record fields are short and mnemonic,
  2653. but they are not completely self-explanatory. This is often the case with
  2654. complex data structures involving access types. There is no way to choose the
  2655. record and field names so that they completely explain the overall
  2656. organization of the records and pointers into a nested set of sorted lists.
  2657. The comments shown are useful in this case. Without them, the reader would not
  2658. know which lists are sorted, which lists are doubly linked, or why. The
  2659. comments express the intent of the author with respect to this complex data
  2660. structure. The maintainer still has to read the code if he wants to be sure
  2661. that the double links are all properly maintained. Keeping this in mind when
  2662. reading the code makes it much easier for him to find a bug where one pointer
  2663. is updated and the opposite one is not.
  2664.  
  2665. 3.3.6   Statement Comments
  2666.  
  2667. guideline
  2668.  
  2669. o       Minimize comments embedded among statements.
  2670.  
  2671. o       Use comments only to explain parts of the code that are not obvious.
  2672.  
  2673. o       Comment intentional omissions from the code.
  2674.  
  2675. o       Do not use comments to paraphrase the code.
  2676.  
  2677. o       Do not use comments to explain remote pieces of code, such as 
  2678. subprograms called by the current unit.
  2679.  
  2680. o       Where comments are necessary, make them visually distinct from the 
  2681. code.
  2682.  
  2683. example
  2684.  
  2685. The following is an example of very poorly commented code:
  2686.  
  2687. ...
  2688.  
  2689. -- Loop through all the strings in the array Strings, converting
  2690. -- them to integers by calling Convert_To_Integer on each one,
  2691. -- accumulating the sum of all the values in Sum, and counting them
  2692. -- in Count.  Then divide Sum by Count to get the average and store
  2693. -- it in Average. Also, record the maximum number in the global
  2694. -- variable Max_Number.
  2695. for I in Strings'Range loop
  2696.    -- Convert each string to an integer value by looping through
  2697.    -- the characters which are digits, until a nondigit is found,
  2698.    -- taking the ordinal value of each, subtracting the ordinal value
  2699.    -- of '0', and multiplying by 10 if another digit follows.  Store
  2700.    -- the result in Number.
  2701.    Number := Convert_To_Integer(Strings(I));
  2702.    -- Accumulate the sum of the numbers in Total.
  2703.    Sum := Sum + Number;
  2704.    -- Count the numbers.
  2705.    Count := Count + 1;
  2706.    -- Decide whether this number is more than the current maximum.
  2707.    if Number > Max_Number then
  2708.       -- Update the global variable Max_Number.
  2709.       Max_Number := Number;
  2710.    end if;
  2711.  
  2712. end loop;
  2713. -- Compute the average.
  2714. Average := Sum / Count;
  2715.  
  2716. The following is improved by not repeating things in the comments which are
  2717. obvious from the code, not describing the details of what goes in inside of
  2718. Convert_To_Integer, deleting an erroneous comment (the one on the statement
  2719. which accumulates the sum), and making the few remaining comments more
  2720. visually distinct from the code.
  2721.  
  2722. Sum_Integers_Converted_From_Strings:
  2723.    for I in Strings'Range loop
  2724.       Number := Convert_To_Integer(Strings(I));
  2725.       Sum := Sum + Number;
  2726.       Count := Count + 1;
  2727.  
  2728.       -- The global Max_Number is computed here for efficiency.
  2729.       if Number > Max_Number then
  2730.      Max_Number := Number;
  2731.       end if;
  2732.  
  2733.    end loop Sum_Integers_Converted_From_Strings;
  2734.  
  2735. Average := Sum / Count;
  2736.  
  2737. rationale
  2738.  
  2739. The improvements shown in the example are not improvements merely by reducing 
  2740. the total number of comments; they are improvements by reducing the number of 
  2741. useless comments.
  2742.  
  2743. Comments that paraphrase or explain obvious aspects of the code have no value. 
  2744. They are a waste of effort for the author to write and the maintainer to 
  2745. update. Therefore, they often end up becoming incorrect. Such comments also 
  2746. clutter the code, hiding the few important comments.
  2747.  
  2748. Comments describing what goes on inside of another unit violate the principle
  2749. of information hiding. The details about Convert_To_Integer (deleted above)
  2750. are irrelevant to the calling unit, and they are better left hidden in case
  2751. the algorithm ever changes. Examples explaining what goes on elsewhere in the
  2752. code are very difficult to maintain and almost always become incorrect at the
  2753. first code modification.
  2754.  
  2755. The advantage of making comments visually distinct from the code is that it
  2756. makes the code easier to scan, and the few important comments stand out
  2757. better.  Highlighting unusual or special code features indicates that they are
  2758. intentional. This assists maintainers by focusing attention on code sections
  2759. that are likely to cause problems during maintenance or when porting the
  2760. program to another implementation.
  2761.  
  2762. Comments should be used to document code that is nonportable, 
  2763. implementation-dependent, environment-dependent, or tricky in any way. They
  2764. notify the reader that something unusual was put there for a reason. A 
  2765. beneficial comment would be one explaining a work-around for a compiler bug. If
  2766. you use a lower level (not "ideal" in the software engineering sense) solution,
  2767. comment on it. Information included in the comments should state why you used 
  2768. that particular construct. Also include documentation on the failed attempts, 
  2769. e.g., using a higher level structure. This type of comment is useful to 
  2770. maintainers for historical purposes.  You show the reader that a significant 
  2771. amount of thought went into the choice of a construct.
  2772.  
  2773. Finally, comments should be used to explain what is not present in the code as 
  2774. well as what is present. If you make a conscious decision to not perform some 
  2775. action, like deallocating a data structure with which you appear to be 
  2776. finished, be sure to add a comment explaining why not. Otherwise, a maintainer 
  2777. may notice the apparent omission and "correct" it later, thus introducing an
  2778. error.
  2779.  
  2780. note
  2781.  
  2782. Further improvements can be made on the above example by declaring the 
  2783. variables Count and Sum in a local block so that their scope is limited and 
  2784. their initializations occur near their usage, e.g., by naming the block 
  2785. Compute_Average or by moving the code into a function called Average_Of. The 
  2786. computation of Max_Number can also be separated from the computation of 
  2787. Average. However, those changes are the subject of other guidelines; this 
  2788. example is only intends to illustrate the proper use of comments.
  2789.  
  2790. 3.3.7   Marker Comments
  2791.  
  2792. guideline
  2793.  
  2794. o       Use pagination markers to mark program unit boundaries (Guideline ).
  2795.  
  2796. o       Repeat the unit name in a comment to mark the begin of a package body, 
  2797. subprogram body, task body, or block if the begin is preceded by declarations.
  2798.  
  2799. o       For long or heavily nested if and case statements, mark the end of the 
  2800. statement with a comment summarizing the condition governing the statement.
  2801.  
  2802. o       For long or heavily nested if statements, mark the else part with a 
  2803. comment summarizing the conditions governing this portion of the statement.
  2804.  
  2805. example
  2806.  
  2807. if    A_Found then
  2808.    ...
  2809. elsif B_Found then
  2810.    ...
  2811.  
  2812. else  -- A and B were both not found
  2813.    ...
  2814.  
  2815.    if Count = Max then
  2816.       ...
  2817.  
  2818.    end if;
  2819.  
  2820.    ...
  2821. end if;  -- A_Found
  2822.  
  2823. ------------------------------------------------------------------------
  2824. package body Abstract_Strings is
  2825.    ...
  2826.  
  2827.    ---------------------------------------------------------------------
  2828.    procedure Catenate (...) is
  2829.    begin
  2830.       ...
  2831.    end Catenate;
  2832.    ---------------------------------------------------------------------
  2833.  
  2834.    ...
  2835. begin  -- Abstract_Strings
  2836.    ...
  2837. end Abstract_Strings;
  2838. ------------------------------------------------------------------------
  2839.  
  2840. rationale
  2841.  
  2842. Marker comments emphasize the structure of code and make it easier to scan. 
  2843. They can be lines that separate sections of code or descriptive tags for a 
  2844. construct. They help the reader resolve questions about the current position in 
  2845. the code. This is more important for large units than for small ones. A short 
  2846. marker comment fits on the same line as the reserved word with which it is 
  2847. associated. Thus, it adds information without clutter.
  2848.  
  2849. The if, elsif, else, and end if of an if statement are often separated by long
  2850. sequences of statements, sometimes involving other if statements. As shown in
  2851. the first example, marker comments emphasize the association of the keywords
  2852. of the same statement over a great visual distance. Marker comments are not
  2853. necessary with the block statement and loop statement because the syntax of
  2854. these statements allows them to be named with the name repeated at the end.
  2855. Using these names is better than using marker comments because the compiler
  2856. verifies that the names at the beginning and end match.
  2857.  
  2858. The sequence of statements of a package body is often very far from the first 
  2859. line of the package. Many subprogram bodies, each containing many begin lines, 
  2860. may occur first. As shown in the second example, the marker comment emphasizes 
  2861. the association of the begin with the package.
  2862.  
  2863. note
  2864.  
  2865. Repeating names and noting conditional expressions clutters the code if 
  2866. overdone. It is visual distance, especially page breaks, that makes marker 
  2867. comments beneficial.
  2868.  
  2869. 3.4     USING TYPES
  2870.  
  2871. Strong typing promotes reliability in software. The type definition of an
  2872. object defines all legal values and operations and allows the compiler to
  2873. check for and identify potential errors during compilation. In addition, the
  2874. rules of type allow the compiler to generate code to check for violations of
  2875. type constraints at execution time. Using these Ada compiler's features
  2876. facilitates earlier and more complete error detection than that which is
  2877. available with less strongly typed languages.
  2878.  
  2879. 3.4.1   Declaring Types
  2880.  
  2881. guideline
  2882.  
  2883. o       Limit the range of scalar types as much as possible.
  2884.  
  2885. o       Seek information about possible values from the application.
  2886.  
  2887. o       Do not overload any of the type names in package Standard.
  2888.  
  2889. o       Use subtype declarations to improve program readability (Booch 1987).
  2890.  
  2891. o       Use derived types and subtypes in concert (see Guideline ).
  2892.  
  2893. example
  2894.  
  2895. subtype Card_Image is String (1 .. 80);
  2896.  
  2897. Input_Line : Card_Image := (others => ' ');
  2898.  
  2899. -- restricted integer type:
  2900. type    Day_Of_Leap_Year     is                  range 1 .. 366;
  2901. subtype Day_Of_Non_Leap_Year is Day_Of_Leap_Year range 1 .. 365;
  2902.  
  2903. By the following declaration, the programmer means, "I haven't the foggiest
  2904. idea how many," but the actual range will show up buried in the code or as a 
  2905. system parameter:
  2906.  
  2907. Employee_Count : Integer;
  2908.  
  2909. rationale
  2910.  
  2911. Eliminating meaningless values from the legal range improves the compiler's 
  2912. ability to detect errors when an object is set to an invalid value. This also 
  2913. improves program readability. In addition, it forces you to carefully think 
  2914. about each use of objects declared to be of the subtype.
  2915.  
  2916. Different implementations provide different sets of values for most of the 
  2917. predefined types. A reader cannot determine the intended range from the 
  2918. predefined names. This situation is aggravated when the predefined names are 
  2919. overloaded.
  2920.  
  2921. The names of an object and its subtype can clarify their intended use and 
  2922. document low-level design decisions. The example above documents a design
  2923. decision to restrict the software to devices whose physical parameters are 
  2924. derived from the characteristics of punch cards. This information is easy to 
  2925. find for any later changes, thus enhancing program maintainability.
  2926.  
  2927. Section 8.5 of the Ada Language Reference Manual says that declaring a subtype 
  2928. without a constraint is one method for renaming a type.
  2929.  
  2930. Types can have highly constrained sets of values without eliminating useful 
  2931. values. Usage as described in Guideline  eliminates many flag variables and 
  2932. type conversions within executable statements. This renders the program more 
  2933. readable while allowing the compiler to enforce strong typing constraints.
  2934.  
  2935. note
  2936.  
  2937. Subtype declarations do not define new types, only constraints for existing 
  2938. types.
  2939.  
  2940. Recognize that any deviation from this guideline detracts from the advantages 
  2941. of the strong typing facilities of the Ada language.
  2942.  
  2943. 3.4.2   Enumeration Types
  2944.  
  2945. guideline
  2946.  
  2947. o       Use enumeration types instead of numeric codes. 
  2948.  
  2949. o       Use representation clauses to match requirements of external devices.
  2950.  
  2951. example
  2952.  
  2953. Use
  2954.  
  2955. type Color is (Blue, Red, Green, Yellow);
  2956.  
  2957. rather than
  2958.  
  2959. Blue   : constant := 1;
  2960. Red    : constant := 2;
  2961. Green  : constant := 3;
  2962. Yellow : constant := 4;
  2963.  
  2964. and add the following if necessary.
  2965.  
  2966. for Color use (Blue   => 1,
  2967.            Red    => 2,
  2968.            Green  => 3,
  2969.            Yellow => 4);
  2970.  
  2971. rationale
  2972.  
  2973. Enumerations are more robust than numeric codes; they leave less potential for 
  2974. errors resulting from incorrect interpretation and from additions to and 
  2975. deletions from the set of values during maintenance. Numeric codes are 
  2976. holdovers from languages that have no user-defined types.
  2977.  
  2978. In addition, Ada provides a number of attributes ('Pos, 'Val, 'Succ, 'Pred, 
  2979. 'Image, and 'Value) for enumeration types which, when used, are more reliable 
  2980. than user-written operations on encodings.
  2981.  
  2982. A numeric code may at first seem appropriate to match external values.  
  2983. Instead, these situations call for a representation clause on the enumeration 
  2984. type. The representation clause documents the "encoding." If the program is
  2985. properly structured to isolate and encapsulate hardware dependencies (see 
  2986. Guideline ), the numeric code ends up in an interface package where it can be 
  2987. easily found and replaced should the requirements change.
  2988.  
  2989. 3.5     SUMMARY
  2990.  
  2991. spelling
  2992.  
  2993. o       Use underscores to separate words in a compound name.
  2994.  
  2995. o       Represent numbers in a consistent fashion. 
  2996.  
  2997. o       Represent literals in a radix appropriate to the problem.
  2998.  
  2999. o       Use underscores to separate digits the same way commas or periods (or 
  3000. spaces for nondecimal bases) would be used in handwritten text. 
  3001.  
  3002. o     When using scientific notation, make the E consistently either upper
  3003. or lower case.
  3004.  
  3005. o     In an alternate base, represent the alphabetic characters in either
  3006. all upper case or all lower case.
  3007.  
  3008. o     Make reserved words and other elements of the program visually
  3009. distinct from each other.
  3010.  
  3011. o       Do not use an abbreviation of a long word as an identifier where a 
  3012. shorter synonym exists.
  3013.  
  3014. o       Use a consistent abbreviation strategy.
  3015.  
  3016. o       Do not use ambiguous abbreviations.
  3017.  
  3018. o       An abbreviation must save many characters over the full word to be 
  3019. justified.
  3020.  
  3021. o       Use abbreviations that are well-accepted in the application domain.
  3022.  
  3023. o    Maintain a list of accepted abbreviations and use only abbreviations
  3024. on that list.
  3025.  
  3026. naming conventions
  3027.  
  3028. o       Choose names that are as self-documenting as possible.
  3029.  
  3030. o       Use a short synonym instead of an abbreviation (see Guideline 3.1.4).
  3031.  
  3032. o       Use names given by the application but not obscure jargon.
  3033.  
  3034. o       Use singular, general nouns as (sub)type identifiers.
  3035.  
  3036. o       Choose identifiers that describe one of the (sub)type's values.
  3037.  
  3038. o     Do not use identifier constructions (e.g., suffixes) that are unique
  3039. to (sub)type identifiers.
  3040.  
  3041. o       Do not use the type names from predefined packages.
  3042.  
  3043. o       Use predicate clauses or adjectives for boolean objects.
  3044.  
  3045. o       Use singular, specific nouns as object identifiers.
  3046.  
  3047. o       Choose identifiers that describe the object's value during execution.
  3048.  
  3049. o       Use singular, general nouns as identifiers for record components.
  3050.  
  3051. o       Use action verbs for procedures and entries.
  3052.  
  3053. o       Use predicate-clauses for boolean functions.
  3054.  
  3055. o       Use nouns for nonboolean functions.
  3056.  
  3057. o       Give packages names that imply higher levels of organization than 
  3058. subprograms. Generally, these are noun phrases that describe the abstraction 
  3059. provided. 
  3060.  
  3061. o       Give tasks names that imply an active entity.  
  3062.  
  3063. o       Name generic subprograms as if they were nongeneric subprograms.
  3064.  
  3065. o       Name generic packages as if they were nongeneric packages.
  3066.  
  3067. o       Make the generic names more general than the instantiated names.
  3068.  
  3069. o       Use symbolic values instead of literals wherever possible.
  3070.  
  3071. o       Use constants instead of variables for constant values.
  3072.  
  3073. o       Use named numbers instead of constants when possible.
  3074.  
  3075. o       Use named numbers to replace numeric literals whose type or context is 
  3076. truly universal.
  3077.  
  3078. o       Use constants for objects whose values cannot change after elaboration 
  3079. (United Technologies 1987).
  3080.  
  3081. o     Show relationships between symbolic values by defining them with
  3082. static expressions.
  3083.  
  3084. o       Use linearly independent sets of literals.
  3085.  
  3086. o       Use attributes like 'First and 'Last instead of literals wherever 
  3087. possible.
  3088.  
  3089. comments
  3090.  
  3091. o       Make the code as clear as possible to reduce the need for comments.
  3092.  
  3093. o     Never repeat information in a comment which is readily available in
  3094. the code.
  3095.  
  3096. o       Where a comment is required, make it concise and complete.
  3097.  
  3098. o       Use proper grammar and spelling in comments.
  3099.  
  3100. o       Make comments visually distinct from the code.
  3101.  
  3102. o       Structure comments in headers so that information can be automatically 
  3103. extracted by a tool.
  3104.  
  3105. o       Put a file header on each source file.
  3106.  
  3107. o       Place ownership, responsibility, and history information for the file 
  3108. in the file header.
  3109.  
  3110. o       Put a header on the specification of each program unit.
  3111.  
  3112. o       Place information required by the user of the program unit in the 
  3113. specification header.
  3114.  
  3115. o       Do not repeat information (except unit name) in the specification 
  3116. header which is present in the specification.
  3117.  
  3118. o       Explain what the unit does, not how or why it does it.
  3119.  
  3120. o       Describe the complete interface to the program unit, including any 
  3121. exceptions it can raise and any global effects it can have.
  3122.  
  3123. o       Do not include information about how the unit fits into the enclosing 
  3124. software system.
  3125.  
  3126. o       Describe the performance (time and space) characteristics of the unit.
  3127.  
  3128. o    Place information required by the maintainer of the program unit in
  3129. the body header.
  3130.  
  3131. o       Explain how and why the unit performs its function, not what the unit 
  3132. does.
  3133.  
  3134. o       Do not repeat information (except unit name) in the header that is 
  3135. readily apparent from reading the code.
  3136.  
  3137. o     Do not repeat information (except unit name) in the body header that
  3138. is available in the specification header.
  3139.  
  3140. o       Comment on all data types, objects, and exceptions unless their names 
  3141. are self-explanatory.
  3142.  
  3143. o       Include information on the semantic structure of complex pointer-based
  3144. data structures.
  3145.  
  3146. o       Include information about relationships that are maintained between 
  3147. data objects.
  3148.  
  3149. o       Do not include comments that merely repeat the information in the name.
  3150.  
  3151. o       Minimize comments embedded among statements.
  3152.  
  3153. o       Use comments only to explain parts of the code that are not obvious.
  3154.  
  3155. o       Comment intentional omissions from the code.
  3156.  
  3157. o       Do not use comments to paraphrase the code.
  3158.  
  3159. o       Do not use comments to explain remote pieces of code, such as 
  3160. subprograms called by the current unit.
  3161.  
  3162. o       Where comments are necessary, make them visually distinct from the 
  3163. code.
  3164.  
  3165. o       Use pagination markers to mark program unit boundaries (Guideline ).
  3166.  
  3167. o       Repeat the unit name in a comment to mark the begin of a package body, 
  3168. subprogram body, task body, or block if the begin is preceded by declarations.
  3169.  
  3170. o       For long or heavily nested if and case statements, mark the end of the 
  3171. statement with a comment summarizing the condition governing the statement.
  3172.  
  3173. o       For long or heavily nested if statements, mark the else part with a 
  3174. comment summarizing the conditions governing this portion of the statement.
  3175.  
  3176. using types
  3177.  
  3178. o       Limit the range of scalar types as much as possible.
  3179.  
  3180. o       Seek information about possible values from the application.
  3181.  
  3182. o       Do not overload any of the type names in package Standard.
  3183.  
  3184. o       Use subtype declarations to improve program readability (Booch 1987).
  3185.  
  3186. o       Use derived types and subtypes in concert (see Guideline ).
  3187.  
  3188. o       Use enumeration types instead of numeric codes. 
  3189.  
  3190. o       Use representation clauses to match requirements of external devices.
  3191.  
  3192.  
  3193.  
  3194.  
  3195. CHAPTER 4
  3196. Program Structure
  3197.  
  3198. Proper structure improves program clarity. This is analogous to readability on
  3199. lower levels and facilitates the use of the readability guidelines (Chapter
  3200. 3). The various program structuring facilities provided by Ada were designed
  3201. to enhance overall clarity of design. These guidelines show how to use these
  3202. facilities for their intended purposes.
  3203.  
  3204. Abstraction and encapsulation are supported by the package concept and by
  3205. private types. Related data and subprograms can be grouped together and seen
  3206. by a higher level as a single entity. Information hiding is enforced via
  3207. strong typing and by the separation of package and subprogram specifications
  3208. from their bodies. Additional Ada language elements that impact program
  3209. structure are exceptions and tasks.
  3210.  
  3211. 4.1     HIGH-LEVEL STRUCTURE
  3212.  
  3213. Well-structured programs are easily understood, enhanced, and maintained.
  3214. Poorly structured programs are frequently restructured during maintenance just 
  3215. to make the job easier. Many of the guidelines listed below are often given as 
  3216. general program design guidelines. 
  3217.  
  3218. 4.1.1   Separate Compilation Capabilities
  3219.  
  3220. guideline
  3221.  
  3222. o     Place the specification of each library unit package in a separate
  3223. file from its body.
  3224.  
  3225. o       Create an explicit specification, in a separate file, for each library 
  3226. unit subprogram.
  3227.  
  3228. o       Use subunits for the bodies of large units which are nested in other 
  3229. units.
  3230.  
  3231. o       Place each subunit in a separate file.
  3232.  
  3233. o       Use a consistent file naming convention.
  3234.  
  3235. example
  3236.  
  3237. The file names below illustrate one possible file organization and associated 
  3238. consistent naming convention. The library unit name is used for the body. A 
  3239. trailing underscore indicates the specification, and any files containing 
  3240. subunits use names constructed by separating the body name from the subunit 
  3241. name with two underscores.
  3242.  
  3243. text_io_.ada                 -- the specification
  3244. text_io.ada                  -- the body
  3245. text_io__integer_io.ada      -- a subunit
  3246. text_io__fixed_io.ada        -- a subunit
  3247. text_io__float_io.ada        -- a subunit
  3248. text_io__enumeration_io.ada  -- a subunit
  3249.  
  3250. rationale
  3251.  
  3252. The main reason for the emphasis on separate files in this guideline is to
  3253. minimize the amount of recompilation required after each change. Typically,
  3254. during software development, bodies of units are updated far more often than
  3255. specifications. If the body and specification reside in the same file, then
  3256. the specification will be compiled each time the body is compiled, even though
  3257. the specification has not changed. Because the specification defines the
  3258. interface between the unit and all of its users, this recompilation of the
  3259. specification typically makes recompilation of all users necessary, in order
  3260. to verify compliance with the specification. If the specifications and bodies
  3261. of the users also reside together, then any users of these units will also
  3262. have to be recompiled, and so on. The ripple effect can force a huge number of
  3263. compilations which could have been avoided, severely slowing the development
  3264. and test phase of a project. This is why we suggest placing specifications of
  3265. all library units (nonnested units) in separate files from their bodies.
  3266.  
  3267. For the same reason, use subunits for large nested bodies, and put each
  3268. subunit in its own file. This makes it possible to modify the body of the one
  3269. nested unit without having to recompile any of the other units in the body.
  3270. This is recommended for large units because changes are more likely to occur
  3271. in large units than in small ones.
  3272.  
  3273. An additional benefit of using multiple separate files is that it allows
  3274. different implementers to modify different parts of the system at the same
  3275. time with conventional editors which do not allow multiple concurrent updates
  3276. to a single file.
  3277.  
  3278. Finally, keeping bodies and specifications separate makes it possible to have
  3279. multiple bodies for the same specification, or multiple specifications for the
  3280. same body. Although Ada requires that there be exactly one specification per
  3281. body in a system at any given time, it can still be useful to maintain
  3282. multiple bodies or multiple specifications for use in different builds of a
  3283. system. For example, a single specification may have multiple bodies, each of
  3284. which implements the same functionality with a different tradeoff of time
  3285. versus space efficiency. Or, for machine-dependent code, there may be one body
  3286. for each target machine. Maintaining multiple package specifications can also
  3287. be useful during development and test. You may develop one specification for
  3288. delivery to your customer and another for unit testing. The first one would
  3289. export only those subprograms intended to be called from outside of the
  3290. package during normal operation of the system. The second one would export all
  3291. subprograms of the package so that each of them could be independently tested.
  3292.  
  3293. A consistent file naming convention is recommended to make it easier to manage 
  3294. the large number of files which may result from following this guideline.
  3295.  
  3296. 4.1.2   Subprograms
  3297.  
  3298. guideline
  3299.  
  3300. o       Use subprograms to enhance abstraction.
  3301.  
  3302. o       Restrict each subprogram to the performance of a single action.
  3303.  
  3304. example
  3305.  
  3306. Your program is required to output text to many types of devices. Because the 
  3307. devices would accept a variety of character sets, the proper way to do this is 
  3308. to write a subprogram to convert to the required character set. This way, the 
  3309. output subprogram has one purpose and the conversions are described elsewhere.
  3310.  
  3311. ...
  3312. ----------------------------------------------------------------------
  3313. procedure Dispatch_To_Device
  3314.       (Output : in     Text;
  3315.        Device      : in     Device_Name;
  3316.        Status      :    out Error_Codes) is
  3317.  
  3318.    Upper_Case_Output : Text (1 .. Output'Length);
  3319.    ...
  3320.  
  3321. begin  -- Dispatch_To_Device
  3322.  
  3323.    ...
  3324.    case Device.Character_Set is
  3325.  
  3326.       when Limited_ASCII =>
  3327.      Convert_To_Upper_Case(Original   => Output,
  3328.                    Upper_Case => Upper_Case_Output);
  3329.      ...
  3330.  
  3331.       when Extended_ASCII =>
  3332.      ...
  3333.  
  3334.       when EBCDIC =>
  3335.      ...
  3336.  
  3337.    end case;  -- Device_Type.Character_Set
  3338.  
  3339.    ...
  3340.  
  3341. end Dispatch_To_Device;
  3342. ----------------------------------------------------------------------
  3343.  
  3344. rationale
  3345.  
  3346. Subprograms are an extremely effective and well-understood abstraction
  3347. technique. Subprograms increase program readability by hiding the details of a 
  3348. particular activity. It is not necessary that a subprogram be called more than 
  3349. once to justify its existence.
  3350.  
  3351. note
  3352.  
  3353. Dealing with the overhead of subroutine calls is discussed in Guideline .
  3354.  
  3355. 4.1.3   Functions
  3356.  
  3357. guideline
  3358.  
  3359. o       Use a function when the subprogram's primary purpose is to provide a 
  3360. single value.
  3361.  
  3362. o       Minimize the side effect of a function.
  3363.  
  3364. example
  3365.  
  3366. Although reading a character from a file will change what character is read 
  3367. next, this is accepted as a minor side effect compared to the primary purpose 
  3368. of the following function:
  3369.  
  3370. function Next_Character return Character is separate;
  3371.  
  3372. However, the use of a function like this should could lead to a subtle
  3373. problem.  Any time the order of evaluation is undefined, the order of the
  3374. values returned by the function will effectively be undefined.  In this
  3375. example, the order of the characters placed in Word and the order that the
  3376. following two characters are given to the Suffix parameters is unknown.  No
  3377. implementation of the Next_Character function can guarantee which character
  3378. will go where:
  3379.  
  3380.    Word : constant String := String'(1 .. 5 => Next_Character);
  3381.  
  3382. begin  -- Start_Parsing
  3383.  
  3384.    Parse(Keyword => Word,
  3385.      Suffix1 => Next_Character,
  3386.      Suffix2 => Next_Character);
  3387. end Start_Parsing;
  3388.  
  3389. Of course, if the order is unimportant (as in a random number generator), then 
  3390. the order of evaluation is unimportant.
  3391.  
  3392. rationale
  3393.  
  3394. A side effect is a change to any variable that is not local to the subprogram.
  3395. This includes changes to variables by other subprograms and entries during
  3396. calls from the function if the changes persist after the function returns.
  3397. Side effects are discouraged because they are difficult to understand and
  3398. maintain.  Additionally, the Ada language does not define the order in which
  3399. functions are evaluated when they occur in expressions or as actual parameters
  3400. to subprograms. Therefore, a program which depends on the order in which side
  3401. effects of functions occur is erroneous. Avoid using side effects anywhere.
  3402.  
  3403. 4.1.4   Packages
  3404.  
  3405. guideline
  3406.  
  3407. o       Use packages for information hiding.
  3408.  
  3409. o       Use packages with private types for abstract data types.
  3410.  
  3411. o       Use packages to model abstract entities appropriate to the problem 
  3412. domain.
  3413.  
  3414. o       Use packages to group together related type and object declarations 
  3415. (e.g., common declarations for two or more library units).
  3416.  
  3417. o       Use packages to group together related program units for configuration 
  3418. control or visibility reasons (NASA 1987).
  3419.  
  3420. o       Encapsulate machine dependencies in packages. Place a software 
  3421. interface to a particular device in a package to facilitate a change to a 
  3422. different device.
  3423.  
  3424. o       Place low-level implementation decisions or interfaces in subprograms
  3425. within packages.
  3426.  
  3427. o       Use packages and subprograms to encapsulate and hide program details 
  3428. that may change (Nissen and Wallis 1984).
  3429.  
  3430. example
  3431.  
  3432. A package called Backing_Storage_Interface could contain type and subprogram 
  3433. declarations to support a generalized view of an external memory system (such 
  3434. as a disk or drum). Its internals may, in turn, depend on other packages more 
  3435. specific to the hardware or operating system.
  3436.  
  3437. rationale
  3438.  
  3439. Packages are the principal structuring facility in Ada. They are intended to
  3440. be used as direct support for abstraction, information hiding, and
  3441. modularization.  For example, they are useful for encapsulating machine
  3442. dependencies as an aid to portability. A single specification can have
  3443. multiple bodies isolating implementation-specific information so other parts
  3444. of the code do not need to change.
  3445.  
  3446. Encapsulating areas of potential change helps to minimize the effort required
  3447. to implement that change by preventing unnecessary dependencies among
  3448. unrelated parts of the system.
  3449.  
  3450. note
  3451.  
  3452. The most prevalent objection to this guideline usually involves performance 
  3453. penalties.  See Guideline  for a discussion about subprogram overhead.
  3454.  
  3455. 4.1.5   Cohesion
  3456.  
  3457. guideline
  3458.  
  3459. o       Make each package serve a single purpose.
  3460.  
  3461. o       Use packages to group related data, types, and subprograms.
  3462.  
  3463. o       Avoid collections of unrelated objects and subprograms (NASA 1987 and 
  3464. Nissen and Wallis 1984).
  3465.  
  3466. example
  3467.  
  3468. As a bad example, a package named Project_Definitions is obviously a "catch
  3469. all" for a particular project and is likely to be a jumbled mess. It probably 
  3470. has this form to permit project members to incorporate a single with clause 
  3471. into their software.
  3472.  
  3473. Better examples are packages called Display_Format_Definitions, containing all 
  3474. the types and constants needed by some specific display in a specific format, 
  3475. and Cartridge_Tape_Handler, containing all the types, constants, and 
  3476. subprograms which provide an interface to a special purpose device.
  3477.  
  3478. rationale
  3479.  
  3480. See also Guideline  on Heterogeneous Data.
  3481.  
  3482. The degree to which the entities in a package are related has a direct impact 
  3483. on the ease of understanding packages and programs made up of packages. There 
  3484. are different criteria for grouping, and some criteria are less effective than 
  3485. others. Grouping the class of data or activity (e.g., initialization modules) 
  3486. or grouping data or activities based on their timing characteristics is less 
  3487. effective than grouping based on function or need to communicate through data 
  3488. (Charette 1986 paraphrased).
  3489.  
  3490. note
  3491.  
  3492. Traditional subroutine libraries often group functionally unrelated
  3493. subroutines. Even such libraries should be broken into a collection of
  3494. packages each containing a logically cohesive set of subprograms.
  3495.  
  3496. 4.1.6   Data Coupling
  3497.  
  3498. guideline
  3499.  
  3500. o       Avoid declaring variables in package specifications.
  3501.  
  3502. example
  3503.  
  3504. This is part of a compiler. Both the package handling error messages and the 
  3505. package containing the code generator need to know the current line number. 
  3506. Rather than storing this in a shared variable of type Natural, the information 
  3507. is stored in a package that hides the details of how such information is 
  3508. represented, and makes it available with access routines.
  3509.  
  3510. -------------------------------------------------------------------------
  3511. package Compilation_Status is
  3512.    type Line_Range is range 1 .. 2_500_000;
  3513.    function Source_Line_Number return Line_Range;
  3514. end Compilation_Status;
  3515.  
  3516. -------------------------------------------------------------------------
  3517.  
  3518. with Compilation_Status;
  3519. package Error_Message_Processing is
  3520.    -- Handle compile-time diagnostic.
  3521. end Error_Message_Processing;
  3522.  
  3523. -------------------------------------------------------------------------
  3524.  
  3525. with Compilation_Status;
  3526.  
  3527. package Code_Generation is
  3528.    -- Operations for code generation.
  3529. end Code_Generation;
  3530. -------------------------------------------------------------------------
  3531.  
  3532. rationale
  3533.  
  3534. Strongly coupled program units can be difficult to debug and very difficult to
  3535. maintain. By protecting shared data with access functions, the coupling is
  3536. lessened. This prevents dependence on the data structure and access to the
  3537. data can be controlled.
  3538.  
  3539. note
  3540.  
  3541. The most prevalent objection to this guideline usually involves performance
  3542. penalties.  When a variable is moved to the package body, subprograms to
  3543. access the variable must be provided and the overhead involved during each
  3544. call to those subprograms is introduced.  See Guideline for a discussion about
  3545. subprogram overhead.
  3546.  
  3547. 4.1.7   Tasks
  3548.  
  3549. guideline
  3550.  
  3551. o       Use tasks to model abstract, asynchronous entities within the problem 
  3552. domain.
  3553.  
  3554. o       Use tasks to control or synchronize access to tasks or other 
  3555. asynchronous entities (e.g., asynchronous I/O, peripheral devices, interrupts).
  3556.  
  3557. o       Use tasks to define concurrent algorithms for multiprocessor 
  3558. architectures.
  3559.  
  3560. o       Use tasks to perform concurrent, cyclic, or prioritized activities 
  3561. (NASA 1987).
  3562.  
  3563. rationale
  3564.  
  3565. The rationale for this guideline is given under Guideline . Chapter 6
  3566. discusses tasking in more detail.
  3567.  
  3568. 4.2     VISIBILITY
  3569.  
  3570. Ada's ability to enforce information hiding and separation of concerns through 
  3571. its visibility controlling features is one of the most important advantages of 
  3572. the language, particularly when "pieces of a large system are being developed
  3573. separately." Subverting these features, for example by excessive reliance on 
  3574. the use clause, is wasteful and dangerous. See also Guideline .
  3575.  
  3576. 4.2.1   Minimization of Interfaces
  3577.  
  3578. guideline
  3579.  
  3580. o       Put only what is needed for the use of a package into its 
  3581. specification.
  3582.  
  3583. o       Minimize the number of declarations in package specifications.
  3584.  
  3585. o       Do not include extra operations simply because they are easy to build.
  3586.  
  3587. o       Minimize the context (with) clauses in a package specification.
  3588.  
  3589. o       Reconsider subprograms which seem to require large numbers of 
  3590. parameters.
  3591.  
  3592. o       Do not manipulate global data within a subprogram or package merely to 
  3593. limit the number of parameters.
  3594.  
  3595. o       Avoid unnecessary visibility; hide the implementation details of a 
  3596. program unit from its users.
  3597.  
  3598. example
  3599.  
  3600. -------------------------------------------------------------------------
  3601. package Telephone_Book is
  3602.  
  3603.    type Listing is limited private;
  3604.  
  3605.    procedure Set_Name (New_Name : in     String;
  3606.                Current  : in out Listing);
  3607.  
  3608.    procedure Insert (Additional : in     Listing);
  3609.    procedure Delete (Obsolete   : in     Listing);
  3610.  
  3611. private
  3612.  
  3613.    type Information;
  3614.    type Listing is access Information;
  3615.  
  3616. end Telephone_Book;
  3617.  
  3618. -------------------------------------------------------------------------
  3619.  
  3620. package body Telephone_Book is
  3621.  
  3622.    -- Full details of record for a listing
  3623.    type Information is
  3624.       record
  3625.      ...
  3626.      Next : Listing;
  3627.       end record;
  3628.  
  3629.    First : Listing;
  3630.  
  3631.    procedure Set_Name (New_Name  : in     String;
  3632.                Current   : in out Listing) is separate;
  3633.    procedure Insert  (Additional : in     Listing) is separate;
  3634.    procedure Delete  (Obsolete   : in     Listing) is separate;
  3635.  
  3636. end Telephone_Book;
  3637. -------------------------------------------------------------------------
  3638.  
  3639. rationale
  3640.  
  3641. For each entity in the specification, give careful consideration to whether it
  3642. could be moved to the body. The fewer the extraneous details, the more
  3643. understandable the program, package, or subprogram. It is important to
  3644. maintainers to know exactly what a package interface is so that they can
  3645. understand the effects of changes. Interfaces to a subprogram extend beyond
  3646. the parameters. Any modification of global data from within a package or
  3647. subprogram is an undocumented interface to the "outside" as well.
  3648.  
  3649. Pushing as many as possible of the context dependencies into the body makes
  3650. the reader's job easier, localizes the recompilation required when library
  3651. units change, and helps prevent a ripple effect during modifications. See also
  3652. Guideline .
  3653.  
  3654. Subprograms with large numbers of parameters often indicate poor design
  3655. decisions (e.g., the functional boundaries of the subprogram are
  3656. inappropriate, or parameters are structured poorly). Conversely, subprograms
  3657. with no parameters are likely to be accessing global data.
  3658.  
  3659. Objects visible within package specifications can be modified by any unit that
  3660. has visibility to them. The object cannot be protected or represented
  3661. abstractly by its enclosing package. Objects which must persist should be
  3662. declared in package bodies. Objects whose value depends on program units
  3663. external to their enclosing package are probably either in the wrong package
  3664. or are better accessed by a subprogram specified in the package specification.
  3665.  
  3666. note
  3667.  
  3668. The specifications of some packages, such as Ada bindings to existing 
  3669. subroutine libraries, cannot easily be reduced in size. In such cases, it may 
  3670. be beneficial to break these up into smaller packages, grouping according to 
  3671. category (e.g., trigonometric functions).
  3672.  
  3673. 4.2.2   Nested Packages
  3674.  
  3675. guideline
  3676.  
  3677. o       Nest package specifications within another package specification only 
  3678. for grouping operations, hiding common implementation details, or presenting 
  3679. different views of the same abstraction.
  3680.  
  3681. example
  3682.  
  3683. Chapter 14 of the Ada Language Reference Manual  gives an example of desirable 
  3684. package specification nesting. The specifications of generic packages 
  3685. Integer_IO, Float_IO, Fixed_IO, and Enumeration_IO are nested within the 
  3686. specification of package Text_IO. Each of them is a generic, grouping closely 
  3687. related operations and needing to use hidden details of the implementation of 
  3688. Text_IO.
  3689.  
  3690. rationale
  3691.  
  3692. Grouping package specifications into an encompassing package emphasizes a 
  3693. relationship of commonality among those packages. It also allows them to share 
  3694. common implementation details resulting from the relationship.
  3695.  
  3696. An abstraction occasionally needs to present different views to different 
  3697. classes of users. Building one view upon another as an additional abstraction 
  3698. does not always suffice, because the functionality of the operations presented 
  3699. by the views may be only partially disjoint. Nesting specifications groups the 
  3700. facilities of the various views, yet associates them with the abstraction they 
  3701. present. Abusive mixing of the views by another unit would be easy to detect 
  3702. due to the multiple use clauses or an incongruous mix of qualified names.
  3703.  
  3704. 4.2.3   Restricting Visibility
  3705.  
  3706. guideline
  3707.  
  3708. o     Restrict the visibility of program units as much as possible by
  3709. nesting them inside other program units and hiding them inside package bodies
  3710. (Nissen and Wallis 1984).
  3711.  
  3712. o       Minimize the scope within which with clauses apply. 
  3713.  
  3714. o       Only with those units directly needed.
  3715.  
  3716. example
  3717.  
  3718. This program is a compiler. Access to the printing facilities of Text_IO is 
  3719. restricted to the software involved in producing the source code listing.
  3720.  
  3721. -------------------------------------------------------------------------
  3722. procedure Compiler is
  3723.  
  3724.    ----------------------------------------------------------------------
  3725.    package Listing_Facilities is
  3726.  
  3727.       procedure New_Page_Of_Listing;
  3728.       procedure New_Line_Of_Print;
  3729.       ...
  3730.  
  3731.    end Listing_Facilities;
  3732.  
  3733.    ----------------------------------------------------------------------
  3734.    package body Listing_Facilities is separate;
  3735.  
  3736. begin  -- Compiler
  3737.    ...
  3738. end Compiler;
  3739.  
  3740. -------------------------------------------------------------------------
  3741.  
  3742. with Text_IO;
  3743.  
  3744. separate (Compiler)
  3745. package body Listing_Facilities is
  3746.  
  3747.    ----------------------------------------------------------------------
  3748.    procedure New_Page_Of_Listing is
  3749.    begin
  3750.       ...
  3751.    end New_Page_Of_Listing;
  3752.  
  3753.    ----------------------------------------------------------------------
  3754.  
  3755.    procedure New_Line_Of_Print is
  3756.    begin
  3757.       ...
  3758.    end New_Line_Of_Print;
  3759.  
  3760.    ...
  3761.  
  3762. end Listing_Facilities;
  3763. -------------------------------------------------------------------------
  3764.  
  3765. rationale
  3766.  
  3767. Restricting visibility of a program unit ensures that the program unit is not
  3768. called from some other part of the system than that which was intended. This
  3769. is done by nesting it inside of the only unit which uses it, or by hiding it
  3770. inside of a package body rather than declaring it in the package
  3771. specification.  This avoids errors and eases the job of maintainers by
  3772. guaranteeing that a local change in that unit will not have an unforeseen
  3773. global effect.
  3774.  
  3775. Restricting visibility of a library unit, by using with clauses on subunits 
  3776. rather than on the entire parent unit, is useful in the same way. In the 
  3777. example above, it is clear that the package Text_IO is used only by the 
  3778. Listing_Facilities package of the compiler.
  3779.  
  3780. note
  3781.  
  3782. One way to minimize the coverage of a with clause is to use it only with 
  3783. subunits that really need it. Consider making those subunits separate 
  3784. compilation units when the need for visibility to a library unit is restricted 
  3785. to a subprogram or two.
  3786.  
  3787. 4.2.4   Hiding Tasks
  3788.  
  3789. guideline
  3790.  
  3791. o       Carefully consider encapsulation of tasks.
  3792.  
  3793. example
  3794.  
  3795. -------------------------------------------------------------------------
  3796. package Disk_Head_Scheduler is
  3797.  
  3798.    type Words        is ...
  3799.  
  3800.    type Track_Number is ...
  3801.  
  3802.    procedure Transmit (Track : in     Track_Number;
  3803.                Data  : in     Words);
  3804.  
  3805.    ...
  3806. end Disk_Head_Scheduler;
  3807.  
  3808. -------------------------------------------------------------------------
  3809.  
  3810. package body Disk_Head_Scheduler is
  3811.  
  3812.    ...
  3813.    task Control is
  3814.       entry Sign_In (Track : in     Track_Number);
  3815.  
  3816.       ...
  3817.    end Control;
  3818.  
  3819.    ----------------------------------------------------------------------
  3820.  
  3821.    task Track_Manager is
  3822.       entry Transfer(Track_Number) (Data : in     Words);
  3823.    end Track_Manager;
  3824.  
  3825.    ----------------------------------------------------------------------
  3826.    ...
  3827.  
  3828.    procedure Transmit (Track : in     Track_Number;
  3829.                Data  : in     Words) is
  3830.    begin
  3831.  
  3832.       Control.Sign_In(Track);
  3833.       Track_Manager.Transfer(Track)(Data);
  3834.  
  3835.    end Transmit;
  3836.  
  3837.    ----------------------------------------------------------------------
  3838.    ...
  3839. end Disk_Head_Scheduler;
  3840. -------------------------------------------------------------------------
  3841.  
  3842. rationale
  3843.  
  3844. The decision whether to declare a task in the specification or body of an 
  3845. enclosing package is not a simple one. There are good arguments for both.
  3846.  
  3847. Hiding a task specification in a package body and exporting (via subprograms)
  3848. only required entries reduces the amount of extraneous information in the
  3849. package specification. It allows your subprograms to enforce any order of
  3850. entry calls necessary to the proper operation of the tasks. It also allows you
  3851. to impose defensive task communication practices (see Guideline ) and proper
  3852. use of conditional and timed entry calls. Finally, it allows the grouping of
  3853. entries into sets for export to different classes of users (e.g., producers
  3854. versus consumers), or the concealment of entries that should not be made
  3855. public at all (e.g., initialization, completion, signals). Where performance
  3856. is an issue and there are no ordering rules to enforce, the entries can be
  3857. renamed as subprograms to avoid the overhead of an extra procedure call.
  3858.  
  3859. An argument which can be viewed as an advantage or disadvantage is that hiding 
  3860. the task specification in a package body hides the fact of a tasking 
  3861. implementation from the user. If the application is such that a change to or 
  3862. from a tasking implementation, or a reorganization of services among tasks, 
  3863. need not concern users of the package then this is an advantage. However, if 
  3864. the package user must know about the tasking implementation to reason about 
  3865. global tasking behavior, then it is better not to hide the task completely. 
  3866. Either move it to the package specification or add comments stating that there 
  3867. is a tasking implementation, describing when a call may block, etc. Otherwise, 
  3868. it is the package implementor's responsibility to ensure that users of the 
  3869. package do not have to concern themselves with behaviors such as deadlock, 
  3870. starvation, and race conditions.
  3871.  
  3872. Finally, keep in mind that hiding tasks behind a procedural interface prevents
  3873. the usage of conditional and timed entry calls and entry families, unless you
  3874. add parameters and extra code to the procedures to make it possible for
  3875. callers to direct the procedures to use these capabilities.
  3876.  
  3877. 4.3     EXCEPTIONS
  3878.  
  3879. This section addresses the issue of exceptions in the context of program
  3880. structures. It discusses how exceptions should be used as part of the
  3881. interface to a unit, including what exceptions to declare and raise and under
  3882. what conditions to raise them. Information on how to handle, propagate, and
  3883. avoid raising exceptions is found in Guideline .  Guidelines on how to deal
  3884. with portability issues are in Guideline .
  3885.  
  3886. 4.3.1   Using Exceptions to Help Define an Abstraction
  3887.  
  3888. guideline
  3889.  
  3890. o       Declare a different exception name for each error that the user of a 
  3891. unit can make.
  3892.  
  3893. o       Declare a different exception name for each unavoidable and 
  3894. unrecoverable internal error which can occur in a unit. 
  3895.  
  3896. o       Do not borrow an exception name from another context.
  3897.  
  3898. o       Export (declare visibly to the user) the names of all exceptions which 
  3899. can be raised.
  3900.  
  3901. o       In a package, document which exceptions can be raised by each 
  3902. subprogram and task entry.
  3903.  
  3904. o       Do not raise exceptions for internal errors which can be avoided or 
  3905. corrected within the unit.
  3906.  
  3907. o       Do not raise the same exception to report different types of errors 
  3908. which are distinguishable by the user of the unit.
  3909.  
  3910. o     Provide interrogative functions which allow the user of a unit to
  3911. avoid causing exceptions to be raised.
  3912.  
  3913. o       When possible, avoid changing state information in a unit before 
  3914. raising an exception.
  3915.  
  3916. o       Catch and convert or handle all predefined and compiler-defined
  3917. exceptions at the earliest opportunity.
  3918.  
  3919. o       Do not explicitly raise predefined or implementation-defined
  3920. exceptions.
  3921.  
  3922. o       Never let an exception propagate beyond its scope.
  3923.  
  3924. example
  3925.  
  3926. This package specification defines an exception which enhances the abstraction:
  3927.  
  3928. -------------------------------------------------------------------------
  3929. generic
  3930.    type Element is private;
  3931. package Stack is
  3932.  
  3933.    function Stack_Empty return Boolean;
  3934.  
  3935.    -- Raised when POP is used on empty stack.
  3936.    No_Data_On_Stack : exception;
  3937.  
  3938.    procedure Pop  (From_Top :    out Element);
  3939.    procedure Push (Onto_Top : in     Element);
  3940.  
  3941. end Stack;
  3942. -------------------------------------------------------------------------
  3943.  
  3944. This example shows how to convert a predefined exception to a user-defined one:
  3945.  
  3946.    ...
  3947.    ----------------------------------------------------------------------
  3948.    procedure Pop (From_Top :    out Element) is
  3949.       ...
  3950.  
  3951.       if Stack_Empty then
  3952.      raise No_Data_On_Stack;
  3953.  
  3954.       else -- Stack contains at least one element
  3955.      Top_Index := Top_Index - 1;
  3956.      From_Top  := Stack(Top_Index + 1);
  3957.  
  3958.       end if;
  3959.    end Pop;
  3960.  
  3961.    ----------------------------------------------------------------------
  3962.    ...
  3963.  
  3964. rationale
  3965.  
  3966. Exceptions should be used as part of an abstraction to indicate error
  3967. conditions which the abstraction is unable to prevent or correct. Since the
  3968. abstraction is unable to correct such an error, it must report the error to
  3969. the user. In the case of a usage error (e.g., attempting to invoke operations
  3970. in the wrong sequence or attempting to exceed a boundary condition), the user
  3971. may be able to correct the error. In the case of an error beyond the control
  3972. of the user, the user may be able to work around the error if there are
  3973. multiple mechanisms available to perform the desired operation. In other
  3974. cases, the user may have to abandon use of the unit, dropping into a degraded
  3975. mode of limited functionality. In any case, the user must be notified.
  3976.  
  3977. Exceptions are a good mechanism for reporting such errors because they provide 
  3978. an alternate flow of control for dealing with errors. This allows 
  3979. error-handling code to be kept separate from the code for normal processing.
  3980. When an exception is raised, the current operation is aborted and control is 
  3981. transferred directly to the appropriate exception handler.
  3982.  
  3983. Several of the guidelines above exist to maximize the ability of the user to
  3984. distinguish and correct different types of errors. Providing a different
  3985. exception name for each error condition makes it possible to handle each error
  3986. condition separately. Declaring new exception names, rather than raising
  3987. exceptions declared in other packages, reduces the coupling between packages
  3988. and also makes different exceptions more distinguishable. Exporting the names
  3989. of all exceptions which a unit can raise, rather than declaring them
  3990. internally to the unit, makes it possible for users of the unit to refer to
  3991. the names in exception handlers. Otherwise, the user would be able to handle
  3992. the exception only with an others handler. Finally, using comments to document
  3993. exactly which of the exceptions declared in a package can be raised by each
  3994. subprogram or task entry making it possible for the user to know which
  3995. exception handlers are appropriate in each situation.
  3996.  
  3997. Because they cause an immediate transfer of control, exceptions are useful for
  3998. reporting unrecoverable errors which prevent an operation from being
  3999. completed, but not for reporting status or modes incidental to the completion
  4000. of an operation. They should not be used to report internal errors which a
  4001. unit was able to correct invisibly to the user.
  4002.  
  4003. To provide the user with maximum flexibility, it is a good idea to provide 
  4004. interrogative functions which the user can call to determine whether an 
  4005. exception would be raised if a subprogram or task entry were invoked. The 
  4006. function Stack_Empty in the above example is such a function. It indicates 
  4007. whether No_Data_On_Stack would be raised if Pop were called.  Providing such 
  4008. functions makes it possible for the user to avoid triggering exceptions.
  4009.  
  4010. To support error recovery by its user, a unit should try to avoid changing 
  4011. state during an invocation which raises an exception. If a requested operation 
  4012. cannot be completely and correctly performed, then the unit should either 
  4013. detect this before changing any internal state information, or should revert 
  4014. back to the state at the time of the request. For example, after raising the 
  4015. exception No_Data_On_Stack, the stack package in the above example should 
  4016. remain in exactly the same state it was in when Pop was called. If it were to 
  4017. partially update its internal data structures for managing the stack, then 
  4018. future Push and Pop operations would not perform correctly. This is always 
  4019. desirable, but not always possible.
  4020.  
  4021. User-defined exceptions should be used instead of predefined or
  4022. compiler-defined exceptions because they are more descriptive and more specific
  4023. to the abstraction. The predefined exceptions are very general, and can be 
  4024. triggered by many different situations. Compiler-defined exceptions are
  4025. nonportable and have meanings which are subject to change even between 
  4026. successive releases of the same compiler. This introduces too much uncertainty 
  4027. for the creation of useful handlers.
  4028.  
  4029. If you are writing an abstraction, remember that the user does not know about 
  4030. the units you use in your implementation. That is an effect of information 
  4031. hiding. If any exception is raised within your abstraction, you must catch it 
  4032. and handle it. The user is not able to provide a reasonable handler if the 
  4033. original exception is allowed to propagate out. You can still convert the 
  4034. exception into a form intelligible to the user if your abstraction cannot 
  4035. effectively recover on its own.
  4036.  
  4037. Converting an exception means raising a user-defined exception in the handler
  4038. for the original exception. This introduces a meaningful name for export to
  4039. the user of the unit. Once the error situation is couched in terms of the
  4040. application, it can be handled in those terms.
  4041.  
  4042. Do not allow an exception to propagate unhandled outside the scope of the 
  4043. declaration of its name, because then only a handler for others can catch it. 
  4044. As discussed under Guideline , a handler for others cannot be written to deal 
  4045. with the specific error effectively.
  4046.  
  4047. 4.4     SUMMARY
  4048.  
  4049. high-level structure
  4050.  
  4051. o     Place the specification of each library unit package in a separate
  4052. file from its body.
  4053.  
  4054. o       Create an explicit specification, in a separate file, for each library 
  4055. unit subprogram.
  4056.  
  4057. o       Use subunits for the bodies of large units which are nested in other 
  4058. units.
  4059.  
  4060. o       Place each subunit in a separate file.
  4061.  
  4062. o       Use a consistent file naming convention.
  4063.  
  4064. o       Use subprograms to enhance abstraction.
  4065.  
  4066. o       Restrict each subprogram to the performance of a single action.
  4067.  
  4068. o       Use a function when the subprogram's primary purpose is to provide a 
  4069. single value.
  4070.  
  4071. o       Minimize the side effect of a function.
  4072.  
  4073. o       Use packages for information hiding.
  4074.  
  4075. o       Use packages with private types for abstract data types.
  4076.  
  4077. o       Use packages to model abstract entities appropriate to the problem 
  4078. domain.
  4079.  
  4080. o       Use packages to group together related type and object declarations 
  4081. (e.g., common declarations for two or more library units).
  4082.  
  4083. o       Use packages to group together related program units for configuration 
  4084. control or visibility reasons.
  4085.  
  4086. o       Encapsulate machine dependencies in packages. Place a software 
  4087. interface to a particular device in a package to facilitate a change to a 
  4088. different device.
  4089.  
  4090. o       Place low-level implementation decisions or interfaces in subprograms
  4091. within packages.
  4092.  
  4093. o       Use packages and subprograms to encapsulate and hide program details 
  4094. that may change.
  4095.  
  4096. o       Make each package serve a single purpose.
  4097.  
  4098. o       Use packages to group functionally related data, types, and 
  4099. subprograms.
  4100.  
  4101. o       Avoid collections of unrelated objects and subprograms.
  4102.  
  4103. o       Avoid putting variables in package specifications.
  4104.  
  4105. o       Use tasks to model abstract, asynchronous entities within the problem 
  4106. domain.
  4107.  
  4108. o       Use tasks to control or synchronize access to tasks or other 
  4109. asynchronous entities (e.g., asynchronous I/O, peripheral devices, interrupts).
  4110.  
  4111. o       Use tasks to define concurrent algorithms for multiprocessor 
  4112. architectures.
  4113.  
  4114. o       Use tasks to perform concurrent, cyclic, or prioritized activities.
  4115.  
  4116. visibility
  4117.  
  4118. o       Put only what is needed for the use of a package into its 
  4119. specification.
  4120.  
  4121. o       Minimize the number of declarations in package specifications.
  4122.  
  4123. o       Do not include extra operations simply because they are easy to build.
  4124.  
  4125. o       Minimize the context (with) clauses in a package specification.
  4126.  
  4127. o       Reconsider subprograms which seem to require large numbers of 
  4128. parameters.
  4129.  
  4130. o       Do not manipulate global data within a subprogram or package merely to 
  4131. limit the number of parameters.
  4132.  
  4133. o       Avoid unnecessary visibility; hide the implementation details of a 
  4134. program unit from its users.
  4135.  
  4136. o       Nest package specifications within another package specification only 
  4137. for grouping operations, hiding common implementation details, or presenting 
  4138. different views of the same abstraction.
  4139.  
  4140. o     Restrict the visibility of program units as much as possible by
  4141. nesting them inside other program units and hiding them inside package bodies.
  4142.  
  4143. o       Minimize the scope within which with clauses apply. 
  4144.  
  4145. o       Only with those units directly needed.
  4146.  
  4147. o       Carefully consider encapsulation of tasks.
  4148.  
  4149. exceptions
  4150.  
  4151. o       Declare a different exception name for each error that the user of a 
  4152. unit can make.
  4153.  
  4154. o       Declare a different exception name for each unavoidable and 
  4155. unrecoverable internal error which can occur in a unit. 
  4156.  
  4157. o       Do not borrow an exception name from another context.
  4158.  
  4159. o       Export (declare visibly to the user) the names of all exceptions which 
  4160. can be raised.
  4161.  
  4162. o       In a package, document which exceptions can be raised by each 
  4163. subprogram and task entry.
  4164.  
  4165. o       Do not raise exceptions for internal errors which can be avoided or 
  4166. corrected within the unit.
  4167.  
  4168. o       Do not raise the same exception to report different types of errors 
  4169. which are distinguishable by the user of the unit.
  4170.  
  4171. o     Provide interrogative functions which allow the user of a unit to
  4172. avoid causing exceptions to be raised.
  4173.  
  4174. o       When possible, avoid changing state information in a unit before 
  4175. raising an exception.
  4176.  
  4177. o       Catch and convert or handle all predefined and compiler-defined
  4178. exceptions at the earliest opportunity.
  4179.  
  4180. o       Do not explicitly raise predefined or implementation-defined
  4181. exceptions.
  4182.  
  4183. o       Never let an exception propagate beyond its scope.
  4184.  
  4185.  
  4186.  
  4187.  
  4188. CHAPTER 5
  4189. Programming Practices
  4190.  
  4191. Software is always subject to change. The need for this change,
  4192. euphemistically known as "maintenance" arises from a variety of sources.
  4193. Errors need to be corrected as they are discovered. System functionality may
  4194. need to be enhanced in planned or unplanned ways. Inevitably, the requirements
  4195. change over the lifetime of the system, forcing continual system evolution.
  4196. Often, these modifications are conducted long after the software was
  4197. originally written, usually by someone other than the original author.
  4198.  
  4199. Easy and successful modification requires that the software be readable,
  4200. understandable, and structured according to accepted practice. If a software
  4201. component cannot be easily understood by a programmer who is familiar with its
  4202. intended function, that software component is not maintainable. Techniques
  4203. that make code readable and comprehensible enhance its maintainability.
  4204. Previous chapters presented techniques such as consistent use of naming
  4205. conventions, clear and well-organized commentary, and proper modularization.
  4206. This chapter presents consistent and logical use of language features.
  4207.  
  4208. Correctness is one aspect of reliability. While style guidelines cannot
  4209. enforce the use of correct algorithms, they can suggest the use of techniques
  4210. and language features known to reduce the number or likelihood of failures.
  4211. Such techniques include program construction methods that reduce the
  4212. likelihood of errors or that improve program predictability by defining
  4213. behavior in the presence of errors.
  4214.  
  4215. 5.1     OPTIONAL PARTS OF THE SYNTAX
  4216.  
  4217. Parts of the Ada syntax, while optional, can enhance the readability of the 
  4218. code. The guidelines given below concern use of some of these optional 
  4219. features.
  4220.  
  4221. 5.1.1   Loop Names
  4222.  
  4223. guideline
  4224.  
  4225. o       Associate names with loops when they are nested (Booch 1987, 1986).
  4226.  
  4227. example 
  4228.  
  4229. Process_Each_Page:
  4230.    loop
  4231.  
  4232.       Process_All_The_Lines_On_This_Page:
  4233.      loop
  4234.  
  4235.         ...
  4236.         exit Process_All_The_Lines_On_This_Page when
  4237.           Line_Number = Max_Lines_On_Page;
  4238.  
  4239.         ...
  4240.         Look_For_Sentinel_Value:
  4241.            loop
  4242.  
  4243.           ...
  4244.           exit Look_For_Sentinel_Value when
  4245.             Current_Symbol = Sentinel;
  4246.  
  4247.           ...
  4248.            end loop Look_For_Sentinel_Value;
  4249.  
  4250.         ...
  4251.      end loop Process_All_The_Lines_On_This_Page;
  4252.  
  4253.       ...
  4254.       exit Process_Each_Page when Page_Number = Maximum_Pages;
  4255.  
  4256.       ...
  4257.    end loop Process_Each_Page;
  4258.  
  4259. rationale
  4260.  
  4261. When you associate a name with a loop, you must include that name with the 
  4262. associated end for that loop (Department of Defense 1983). This helps readers 
  4263. find the associated end for any given loop. This is especially true if loops 
  4264. are broken over screen or page boundaries. The choice of a good name for the 
  4265. loop documents its purpose, reducing the need for explanatory comments. If a 
  4266. name for a loop is very difficult to choose, this could indicate a need for 
  4267. more thought about the algorithm.
  4268.  
  4269. Regularly naming loops helps you follow Guideline .
  4270.  
  4271. It can be difficult to think up a name for every loop, therefore the guideline
  4272. specifies nested loops. The benefits in readability and second thought
  4273. outweigh the inconvenience of naming the loops.
  4274.  
  4275. 5.1.2   Block Names
  4276.  
  4277. guideline
  4278.  
  4279. o       Associate names with blocks when they are nested.
  4280.  
  4281. example 
  4282.  
  4283. Trip:
  4284.    declare
  4285.       ...
  4286.    begin  -- Trip
  4287.  
  4288.       Arrive_At_Airport:
  4289.      declare
  4290.         ...
  4291.      begin  -- Arrive_At_Airport
  4292.  
  4293.         Rent_Car;
  4294.         Claim_Baggage;
  4295.         Reserve_Hotel;
  4296.  
  4297.         ...
  4298.      end Arrive_At_Airport;
  4299.  
  4300.       Visit_Customer:
  4301.      declare
  4302.         ...
  4303.      begin  -- Visit_Customer
  4304.         -- again a set of activities...
  4305.         ...
  4306.      end Visit_Customer;
  4307.  
  4308.       Departure_Preparation:
  4309.      declare
  4310.         ...
  4311.      begin  -- Departure_Preparation
  4312.         Return_Car;
  4313.         Check_Baggage;
  4314.         Wait_For_Flight;
  4315.  
  4316.         ...
  4317.      end Departure_Preparation;
  4318.  
  4319.       Board_Return_Flight;
  4320.    end Trip;
  4321.  
  4322. rationale
  4323.  
  4324. When there is a nested block structure it can be difficult to determine which 
  4325. end corresponds to which block. Naming blocks alleviates this confusion. The 
  4326. choice of a good name for the block documents its purpose, reducing the need 
  4327. for explanatory comments. If a name for the block is very difficult to choose, 
  4328. this could indicate a need for more thought about the algorithm.
  4329.  
  4330. This guideline is also useful if nested blocks are broken over a screen or
  4331. page boundary.
  4332.  
  4333. It can be difficult to think up a name for each block, therefore the guideline 
  4334. specifies nested blocks. The benefits in readability and second thought 
  4335. outweigh the inconvenience of naming the blocks.
  4336.  
  4337. 5.1.3   Exit Statements
  4338.  
  4339. guideline
  4340.  
  4341. o       Use loop names on all exit statements from nested loops.
  4342.  
  4343. example
  4344.  
  4345. See the example in Guideline .
  4346.  
  4347. rationale
  4348.  
  4349. An exit statement is an implicit goto. It should specify its source
  4350. explicitly.  When there is a nested loop structure and an exit statement is
  4351. used, it can be difficult to determine which loop is being exited. Also,
  4352. future changes which may introduce a nested loop are likely to introduce an
  4353. error, with the exit accidentally exiting from the wrong loop. Naming loops
  4354. and their exits alleviates this confusion. This guideline is also useful if
  4355. nested loops are broken over a screen or page boundary.
  4356.  
  4357. 5.1.4   Naming End Statements
  4358.  
  4359. guideline
  4360.  
  4361. o       Include the simple name at the end of a package specification and body.
  4362.  
  4363. o       Include the simple name at the end of a task specification and body.
  4364.  
  4365. o       Include the simple name at the end of an accept statement.
  4366.  
  4367. o       Include the designator at the end of a subprogram body. 
  4368.  
  4369. example
  4370.  
  4371. ------------------------------------------------------------------------
  4372. package Autopilot is
  4373.  
  4374.    function Is_Engaged return Boolean;
  4375.  
  4376.    procedure Engage;
  4377.    procedure Disengage;
  4378.  
  4379. end Autopilot;
  4380.  
  4381. ------------------------------------------------------------------------
  4382.  
  4383. package body Autopilot is
  4384.  
  4385.    ...
  4386.  
  4387.    ---------------------------------------------------------------------
  4388.    task Course_Monitor is
  4389.       entry Reset (Engage : in     Boolean);
  4390.    end Course_Monitor;
  4391.  
  4392.    ---------------------------------------------------------------------
  4393.    function Is_Engaged return Boolean is
  4394.    ...
  4395.    end Is_Engaged;
  4396.  
  4397.    ---------------------------------------------------------------------
  4398.    procedure Engage is
  4399.    ...
  4400.    end Engage;
  4401.  
  4402.    ---------------------------------------------------------------------
  4403.    procedure Disengage is
  4404.    ...
  4405.    end Disengage;
  4406.  
  4407.    ---------------------------------------------------------------------
  4408.    task body Course_Monitor is
  4409.    ...
  4410.      accept Reset (Engage : in     Boolean) do
  4411.  
  4412.         ...
  4413.  
  4414.      end Reset;
  4415.  
  4416.    ...
  4417.    end Course_Monitor;
  4418.  
  4419.    ---------------------------------------------------------------------
  4420. end Autopilot;
  4421. ------------------------------------------------------------------------
  4422.  
  4423. rationale
  4424.  
  4425. Repeating names on the end of these compound statements ensures consistency 
  4426. throughout the code. In addition, the named end provides a reference for the 
  4427. reader if the unit spans a page or screen boundary, or if it contains a nested 
  4428. unit.
  4429.  
  4430. 5.2     PARAMETER LISTS
  4431.  
  4432. A subprogram or entry parameter list is the interface to the abstraction 
  4433. implemented by the subprogram or entry. It is important that it is clear and 
  4434. that it is expressed in a consistent style. Careful decisions about formal 
  4435. parameter naming and ordering can make the purpose of the subprogram easier to 
  4436. understand which can make it easier to use.
  4437.  
  4438. 5.2.1   Formal Parameters
  4439.  
  4440. guideline
  4441.  
  4442. o       Name formal parameters descriptively to reduce the need for comments.
  4443.  
  4444. example
  4445.  
  4446. List_Manager.Insert (Element     => New_Employee,
  4447.              Into_List   => Probationary_Employees,
  4448.              At_Position => 1);
  4449.  
  4450. rationale
  4451.  
  4452. Following the variable naming guidelines (Guidelines and ) for formal
  4453. parameters can make calls to subprograms read more like regular prose, as
  4454. shown in the example above where no comments are necessary. Descriptive names
  4455. of this sort can also make the code in the body of the subprogram more clear.
  4456.  
  4457. 5.2.2   Named Association
  4458.  
  4459. guideline
  4460.  
  4461. o       Use named parameter association in calls of infrequently used 
  4462. subprograms or entries with many formal parameters.
  4463.  
  4464. o       Use named association when instantiating generics.
  4465.  
  4466. o       Use named association for clarification when the actual parameter is 
  4467. any literal or expression.
  4468.  
  4469. o       Use named association when supplying a nondefault value to an optional 
  4470. parameter.
  4471.  
  4472. instantiation
  4473.  
  4474. -     Use named parameter association in calls of subprograms or entries
  4475. called from less than five places in a single source file or with more than
  4476. two formal parameters.
  4477.  
  4478. example
  4479.  
  4480. Encode_Telemetry_Packet (Source         => Power_Electronics,
  4481.              Content        => Temperature,
  4482.              Value          =>
  4483.                 Read_Temperature_Sensor(Power_Electronics),
  4484.              Time           => Current_Time,
  4485.              Sequence       => Next_Packet_ID,
  4486.              Vehicle        => This_Spacecraft,
  4487.              Primary_Module => True);
  4488.  
  4489. rationale
  4490.  
  4491. Calls of infrequently used subprograms or entries with many formal parameters 
  4492. can be difficult to understand without referring to the subprogram or entry 
  4493. code. Named parameter association can make these calls more readable.
  4494.  
  4495. When the formal parameters have been named appropriately, it is easier to
  4496. determine exactly what purpose the subprogram serves without looking at its
  4497. code. This reduces the need for named constants that exist solely to make
  4498. calls more readable. It also allows variables used as actual parameters to be
  4499. given names indicating what they are without regard to why they are being
  4500. passed in a call. An actual parameter, which is an expression rather than a
  4501. variable, cannot be named otherwise.
  4502.  
  4503. Named association allows subprograms to have new parameters inserted with 
  4504. minimal ramifications to existing calls.
  4505.  
  4506. note
  4507.  
  4508. The judgment of when named parameter association improves readability is
  4509. subjective. Certainly, simple or familiar subprograms such as a swap routine
  4510. or a sine function do not require the extra clarification of named association
  4511. in the procedure call.
  4512.  
  4513. caution
  4514.  
  4515. A consequence of named parameter association is that the formal parameter
  4516. names may not be changed without modifying the text of each call.
  4517.  
  4518. 5.2.3   Default Parameters
  4519.  
  4520. guideline
  4521.  
  4522. o       Provide default parameters to allow for occasional, special use of 
  4523. widely used subprograms or entries.
  4524.  
  4525. o       Place default parameters at the end of the formal parameter list.
  4526.  
  4527. o       Consider providing default values to new parameters added to an 
  4528. existing subprogram.
  4529.  
  4530. example
  4531.  
  4532. Chapter 14 of the Ada Language Reference Manual (Department of Defense 1983) 
  4533. contains many examples of this practice.
  4534.  
  4535. rationale
  4536.  
  4537. Often, the majority of uses of a subprogram or entry need the same value for a 
  4538. given parameter. Providing that value, as the default for the parameter, makes 
  4539. the parameter optional on the majority of calls. It also allows the remaining 
  4540. calls to customize the subprogram or entry by providing different values for 
  4541. that parameter.
  4542.  
  4543. Placing default parameters at the end of the formal parameter list allows the 
  4544. caller to use positional association on the call, otherwise defaults are 
  4545. available only when named association is used.
  4546.  
  4547. Often during maintenance activities, you increase the functionality of a
  4548. subprogram or entry. This requires more parameters than the original form for
  4549. some calls. New parameters may be required to control this new functionality.
  4550. Give the new parameters default values which specify the old functionality.
  4551. Calls needing the old functionality need not be changed; they take the
  4552. defaults. This is true if the new parameters are added to the end of the
  4553. parameter list, or if named association is used on all calls. New calls
  4554. needing the new functionality can specify that by providing other values for
  4555. the new parameters.
  4556.  
  4557. This enhances maintainability in that the places which use the modified 
  4558. routines do not themselves have to be modified, while the previous 
  4559. functionality levels of the routines are allowed to be "reused."
  4560.  
  4561. exceptions
  4562.  
  4563. Do not go overboard. If the changes in functionality are truly radical, you 
  4564. should be preparing a separate routine rather than modifying an existing one. 
  4565. One indicator of this situation would be that it is difficult to determine 
  4566. value combinations for the defaults that uniquely and naturally require the 
  4567. more restrictive of the two functions. In such cases, it is better to go ahead 
  4568. with creation of a separate routine.
  4569.  
  4570. 5.2.4   Mode Indication
  4571.  
  4572. guideline
  4573.  
  4574. o       Show the mode indication of all procedure and entry parameters (Nissen 
  4575. and Wallis 1984).
  4576.  
  4577. o       Use in out only when the parameter is both read from and updated.
  4578.  
  4579. example
  4580.  
  4581. procedure Open_File (File_Name   : in     String;
  4582.              Open_Status :    out Status_Codes);
  4583.  
  4584. entry Acquire (Key      : in     Capability;
  4585.            Resource :    out Tape_Drive);
  4586.  
  4587. rationale
  4588.  
  4589. By showing the mode of parameters, you aid the reader. If you do not specify a 
  4590. parameter mode, the default mode is in. Explicitly showing the mode indication 
  4591. of all parameters is a more assertive action than simply taking the default 
  4592. mode. Anyone reviewing the code later will be more confident that you intended 
  4593. the parameter mode to be in.
  4594.  
  4595. Use the mode that reflects the actual use of the parameter. Only use in out 
  4596. mode when reading and writing to a parameter.
  4597.  
  4598. exception
  4599.  
  4600. It may be necessary to consider several alternative implementations for a
  4601. given abstraction.  For example, a bounded stack can be implemented as a
  4602. pointer to an array.  Even though an update to the object being pointed to
  4603. does not require changing the pointer value itself, you may want to consider
  4604. making the mode in out to allow changes to the implementation and to document
  4605. more accurately what the operation is doing.  If you later change the
  4606. implementation to a simple array, the mode will have to be in out, potentially
  4607. causing changes to all places that the routine is called.
  4608.  
  4609. 5.3     TYPES
  4610.  
  4611. In addition to determining the possible values for variables, type names, and 
  4612. distinctions can be very valuable aids in developing safe, readable, and 
  4613. understandable code. Types clarify the structure of your data and can limit or 
  4614. restrict the operations performed on that data. "Keeping types distinct has
  4615. been found to be a very powerful means of detecting logical mistakes when a 
  4616. program is written and to give valuable assistance whenever the program is 
  4617. being subsequently maintained." (Pyle 1985)  Take advantage of Ada's strong 
  4618. typing capability in the form of subtypes, derived types, task types, private 
  4619. types, and limited private types.
  4620.  
  4621. The guidelines encourage much code to be written to ensure strong typing
  4622. (i.e., subtypes). While it might appear that there would be execution
  4623. penalties for this amount of code, this is usually not the case. In contrast
  4624. to other conventional languages, Ada has a less direct relationship between
  4625. the amount of code that is written and the size of the resulting executable
  4626. program. Most of the strong type checking is performed at compilation time
  4627. rather than execution time, so the size of the executable code is not greatly
  4628. affected.
  4629.  
  4630. 5.3.1   Derived Types and Subtypes
  4631.  
  4632. guideline
  4633.  
  4634. o       Use existing types as building blocks by deriving new types from them.
  4635.  
  4636. o       Use range constraints on subtypes.
  4637.  
  4638. o       Define new types, especially derived types, to include the largest set 
  4639. of possible values, including boundary values.
  4640.  
  4641. o    Constrain the ranges of derived types with subtypes, excluding
  4642. boundary values.
  4643.  
  4644. example
  4645.  
  4646. Type Table is a building block for the creation of new types:
  4647.  
  4648. type Table is
  4649.    record
  4650.       Count : List_Size  := Empty;
  4651.       List  : Entry_List := Empty_List;
  4652.    end record;
  4653.  
  4654. type Telephone_Directory  is new Table;
  4655. type Department_Inventory is new Table;
  4656.  
  4657. The following are distinct types that cannot be intermixed in operations that 
  4658. are not programmed explicitly to use them both:
  4659.  
  4660. type Dollars is new Number;
  4661. type Cents   is new Number;
  4662.  
  4663. Below, Source_Tail has a value outside the range of Listing_Paper when the
  4664. line is empty. All the indices can be mixed in expressions, as long as the
  4665. results fall within the correct subtypes:
  4666.  
  4667. type Columns          is range First_Column - 1 .. Listing_Width + 1;
  4668. subtype Listing_Paper is
  4669.       Columns range First_Column .. Listing_Width;
  4670. subtype Dumb_Terminal is
  4671.       Columns range First_Column .. Dumb_Terminal_Width;
  4672.  
  4673. type Line             is array (Columns range <>) of Bytes;
  4674. subtype Listing_Line  is Line (Listing_Paper);
  4675. subtype Terminal_Line is Line (Dumb_Terminal);
  4676.  
  4677. Source_Tail : Columns       := Columns'First;
  4678. Source      : Listing_Line;
  4679. Destination : Terminal_Line;
  4680.  
  4681. ...
  4682.  
  4683. Destination(Destination'First .. Source_Tail - Destination'Last) :=
  4684.       Source(Columns'Succ(Destination'Last) .. Source_Tail);
  4685.  
  4686. rationale
  4687.  
  4688. The name of a derived type can make clear its intended use and avoid
  4689. proliferation of similar type definitions. Objects of two derived types, even
  4690. though derived from the same type, cannot be mixed in operations unless such
  4691. operations are supplied explicitly or one is converted to the other
  4692. explicitly.  This prohibition is an enforcement of strong typing.
  4693.  
  4694. Define new types, derived types, and subtypes cautiously and deliberately. The 
  4695. concepts of subtype and derived type are not equivalent, but they can be used 
  4696. to advantage in concert. A subtype limits the range of possible values for a 
  4697. type, but does not define a new type.
  4698.  
  4699. Types can have highly constrained sets of values without eliminating useful 
  4700. values. Used in concert, derived types and subtypes can eliminate many flag 
  4701. variables and type conversions within executable statements. This renders the 
  4702. program more readable, enforces the abstraction, and allows the compiler to 
  4703. enforce strong typing constraints.
  4704.  
  4705. Many algorithms begin or end with values just outside the normal range. If
  4706. boundary values are not compatible within subexpressions, algorithms can be
  4707. needlessly complicated. The program can become cluttered with flag variables
  4708. and special cases when it could just test for zero or some other sentinel
  4709. value just outside normal range.
  4710.  
  4711. The type Columns and the subtype Listing_Paper in the example above
  4712. demonstrate how to allow sentinel values. The subtype Listing_Paper could be
  4713. used as the type for parameters of subprograms declared in the specification
  4714. of a package.  This would restrict the range of values which could be
  4715. specified by the caller.  Meanwhile, the type COLUMNS could be used to store
  4716. such values internally to the body of the package, allowing First_Column - 1
  4717. to be used as a sentinel value. This combination of types and subtypes allows
  4718. compatibility between subtypes within subexpressions without type conversions
  4719. as would happen with derived types.
  4720.  
  4721. note
  4722.  
  4723. The price of the reduction in the number of independent type declarations is 
  4724. that subtypes and derived types change when the base type is redefined. This 
  4725. trickle-down of changes is sometimes a blessing and sometimes a curse. However,
  4726. usually it is intended and beneficial.
  4727.  
  4728. 5.3.2   Anonymous Types
  4729.  
  4730. guideline
  4731.  
  4732. o       Avoid anonymous types.
  4733.  
  4734. o       Use anonymous types for array variables when no suitable type exists 
  4735. and the array will not be referenced as a whole.
  4736.  
  4737. example
  4738.  
  4739. Use
  4740.  
  4741. type Buffer_Index is range 1 .. 80;
  4742. type Buffer       is array (Buffer_Index) of Character;
  4743.  
  4744. Input_Line : Buffer;
  4745.  
  4746. rather than
  4747.  
  4748. Input_Line : array (Buffer_Index) of Character;
  4749.  
  4750. rationale
  4751.  
  4752. Although Ada allows anonymous types, they have limited usefulness and 
  4753. complicate program modification. For example, except for arrays, a variable of 
  4754. anonymous type can never be used as an actual parameter because it is not 
  4755. possible to define a formal parameter of the same type. Even though this may 
  4756. not be a limitation initially, it precludes a modification in which a piece of 
  4757. code is changed to a subprogram. Also, two variables declared using the same 
  4758. anonymous type declaration are actually of different types.
  4759.  
  4760. Even though the implicit conversion of array types during parameter passing is
  4761. supported in Ada, it is difficult to justify not using the type of the
  4762. parameter.  In most situations, the type of the parameter is visible and
  4763. easily substituted in place of an anonymous array type.  The use of an
  4764. anonymous array type implies that the array is only being used as a convenient
  4765. way to implement a collection of values.  It is misleading to use an anonymous
  4766. type and then treat the variable as an object.
  4767.  
  4768. note
  4769.  
  4770. For anonymous task types, see Guideline .
  4771.  
  4772. In reading the Ada Language Reference Manual (Department of Defense 1983), you 
  4773. will notice that there are cases when anonymous types are mentioned abstractly 
  4774. as part of the description of the Ada computational model. These cases do not 
  4775. violate this guideline.
  4776.  
  4777. 5.3.3   Private Types
  4778.  
  4779. guideline
  4780.  
  4781. o       Use limited private types in preference to private types. 
  4782.  
  4783. o       Use private types in preference to nonprivate types.
  4784.  
  4785. o       Explicitly export needed operations rather than easing restrictions.
  4786.  
  4787. example
  4788.  
  4789. ------------------------------------------------------------------------
  4790. package Packet_Telemetry is
  4791.  
  4792.    type Frame_Header is limited private;
  4793.    type Frame_Data   is private;
  4794.    type Frame_Codes  is (Main_Bus_Voltage, Transmitter_1_Power);
  4795.  
  4796.    ...
  4797. private
  4798.  
  4799.    type Frame_Header is
  4800.       record
  4801.      ...
  4802.       end record;
  4803.  
  4804.    type Frame_Data is
  4805.       record
  4806.      ...
  4807.       end record;
  4808.  
  4809.    ...
  4810. end Packet_Telemetry;
  4811. ------------------------------------------------------------------------
  4812.  
  4813. rationale
  4814.  
  4815. Limited private types and private types support abstraction and information 
  4816. hiding better than nonprivate types. The more restricted the type, the better 
  4817. information hiding is served. This, in turn, allows the implementation to 
  4818. change without affecting the rest of the program. While there are many valid 
  4819. reasons to export types, it is better to try the preferred route first, 
  4820. loosening the restrictions only as necessary. If it is necessary for a user of 
  4821. the package to use a few of the restricted operations, it is better to export 
  4822. the operations explicitly and individually via exported subprograms than to 
  4823. drop a level of restriction. This practice retains the restrictions on other 
  4824. operations. 
  4825.  
  4826. Limited private types have the most restricted set of operations available to 
  4827. users of a package. Of the types that must be made available to users of a 
  4828. package, as many as possible should be limited private. The operations 
  4829. available to limited private types are membership tests, selected components, 
  4830. components for the selections of any discriminant, qualification and explicit 
  4831. conversion, and attributes 'Base and 'Size. Objects of a limited private type 
  4832. also have the attribute 'Constrained if there are discriminants. None of these 
  4833. operations allow the user of the package to manipulate objects in a way that 
  4834. depends on the structure of the type.
  4835.  
  4836. If additional operations must be available to the type, the restrictions may
  4837. be loosened by making it a private type. The operations available on objects
  4838. of nprivate types that are not available on objects of limited private types
  4839. are assignment and tests for equality and inequality. There are advantages to
  4840. the restrictive nature of limited private types. For example, assignment
  4841. allows copies of an object to be made. This could be a problem if the object's
  4842. type is a pointer.
  4843.  
  4844. note
  4845.  
  4846. The predefined packages Direct_IO and Sequential_IO do not accept limited 
  4847. private types as generic parameters.  This restriction should be considered 
  4848. when I/O operations are needed for a type.
  4849.  
  4850. 5.4     DATA STRUCTURES
  4851.  
  4852. The data structuring capabilities of Ada are a powerful resource; therefore,
  4853. nuse them to model the data as closely as possible. It is possible to group
  4854. logically related data and let the language control the abstraction and
  4855. operations on the data rather than requiring the programmer or maintainer to
  4856. do so. Data can also be organized in a building block fashion. In addition to
  4857. showing how a data structure is organized (and possibly giving the reader an
  4858. indication as to why it was organized that way), creating the data structure
  4859. from smaller components allows those components to be reused themselves. Using
  4860. the features that Ada provides can increase the maintainability of your code.
  4861.  
  4862. 5.4.1   Heterogeneous Data
  4863.  
  4864. guideline
  4865.  
  4866. o       Use records to group heterogeneous but related data.
  4867.  
  4868. o       Consider records to map to I/O device data.
  4869.  
  4870. example
  4871.  
  4872. type Propulsion_Method is (Sail, Diesel, Nuclear);
  4873.  
  4874. type Craft is
  4875.    record
  4876.       Name   : Common_Name;
  4877.       Plant  : Propulsion_Method;
  4878.       Length : Feet;
  4879.       Beam   : Feet;
  4880.       Draft  : Feet;
  4881.    end record;
  4882.  
  4883. type Fleet is array (1 .. Fleet_Size) of Craft;
  4884.  
  4885. rationale
  4886.  
  4887. You help the maintainer find all of the related data by gathering it into the 
  4888. same construct, simplifying any modifications that apply to all rather than 
  4889. part. This in turn increases reliability. Neither you nor an unknown maintainer 
  4890. are liable to forget to deal with all the pieces of information in the 
  4891. executable statements, especially if updates are done with aggregate 
  4892. assignments whenever possible.
  4893.  
  4894. The idea is to put the information a maintainer needs to know where it can be
  4895. found with the minimum of effort. For example, if all information relating to
  4896. a given Craft is in the same place, the relationship is clear both in the
  4897. declarations and especially in the code accessing and updating that
  4898. information. But, if it is scattered among several data structures, it is less
  4899. obvious that this is an intended relationship as opposed to a coincidental
  4900. one.  In the latter case, the declarations may be grouped together to imply
  4901. intent, but it may not be possible to group the accessing and updating code
  4902. that way.  Ensuring the use of the same index to access the corresponding
  4903. element in each of several parallel arrays is difficult if the accesses are at
  4904. all scattered.
  4905.  
  4906. If the application must interface directly to hardware, the use of records, 
  4907. especially in conjunction with record representation clauses, could be useful 
  4908. to map onto the layout of the hardware in question.
  4909.  
  4910. note
  4911.  
  4912. It may seem desirable to store heterogeneous data in parallel arrays in what 
  4913. amounts to a FORTRAN-like style. This style is an artifact of FORTRAN's data
  4914. structuring limitations. FORTRAN only has facilities for constructing 
  4915. homogeneous arrays. Ada's variant record types offer one way to specify what 
  4916. are called nonhomogeneous arrays or heterogeneous arrays.
  4917.  
  4918. exceptions
  4919.  
  4920. If the application must interface directly to hardware, and the hardware 
  4921. requires that information be distributed among various locations, then it may 
  4922. not be possible to use records.
  4923.  
  4924. 5.4.2   Nested Records
  4925.  
  4926. guideline
  4927.  
  4928. o       Record structures should not always be flat. Factor out common parts.
  4929.  
  4930. o       For a large record structure, group related components into smaller 
  4931. subrecords.
  4932.  
  4933. o       For nested records, pick element names that read well when inner 
  4934. elements are referenced.
  4935.  
  4936. example
  4937.  
  4938. type Coordinate is
  4939.    record
  4940.       Row    : Local_Float;
  4941.       Column : Local_Float;
  4942.    end record;
  4943.  
  4944. type Window is
  4945.    record
  4946.       Top_Left     : Coordinate;
  4947.       Bottom_Right : Coordinate;
  4948.    end record;
  4949.  
  4950. rationale
  4951.  
  4952. You can make complex data structures understandable and comprehensible by
  4953. composing them of familiar building blocks. This technique works especially
  4954. well for large record types with parts which fall into natural groupings. The
  4955. components factored into separately declared records, based on a common
  4956. quality or purpose, correspond to a lower level of abstraction than that
  4957. represented by the larger record.
  4958.  
  4959. note
  4960.  
  4961. A carefully chosen name for the component of the larger record that is used to 
  4962. select the smaller enhances readability, for example: 
  4963.  
  4964.  
  4965. if Window1.Bottom_Right.Row > Window2.Top_Left.Row then . . . 
  4966.  
  4967. 5.4.3   Dynamic Data
  4968.  
  4969. guideline
  4970.  
  4971. o       Differentiate between static and dynamic data. Use dynamically 
  4972. allocated objects with caution.
  4973.  
  4974. o       Use dynamically allocated data structures only when it is necessary to 
  4975. create and destroy them dynamically or to be able to reference them by 
  4976. different names.
  4977.  
  4978. o       Do not drop pointers to undeallocated objects.
  4979.  
  4980. o       Do not leave dangling references to deallocated objects.
  4981.  
  4982. o       Initialize all access variables and components within a record.
  4983.  
  4984. o       Do not rely on memory deallocation.
  4985.  
  4986. o       Deallocate explicitly.
  4987.  
  4988. o       Use length clauses to specify total allocation size.
  4989.  
  4990. o       Provide handlers for Storage_Error.
  4991.  
  4992. example
  4993.  
  4994. These lines show how a dangling reference might be created:
  4995.  
  4996. P1 := new Object;
  4997. P2 := P1;
  4998. Unchecked_Object_Deallocation(P2);
  4999.  
  5000. This line can raise an exception due to referencing the deallocated object:
  5001.  
  5002. X := P1.all;
  5003.  
  5004. In the following three lines, if there is no intervening assignment of the 
  5005. value of P1 to any other pointer, the object created on the first line is no 
  5006. longer accessible after the third line. The only pointer to the allocated 
  5007. object has been dropped.
  5008.  
  5009. P1 := new Object;
  5010. ...
  5011. P1 := P2;
  5012.  
  5013. rationale
  5014.  
  5015. See also Guidelines , , and for variations on these problems. A dynamically
  5016. allocated object is an object created by the execution of an allocator
  5017. ("new").  Allocated objects referenced by access variables allow you to
  5018. generate aliases, which are multiple references to the same object. Anomalous
  5019. behavior can arise when you reference a deallocated object by another name.
  5020. This is called a dangling reference. Totally disassociating a still-valid
  5021. object from all names is called dropping a pointer. A dynamically allocated
  5022. object that is not associated with a name cannot be referenced or explicitly
  5023. deallocated.
  5024.  
  5025. A dropped pointer depends on an implicit memory manager for reclamation of
  5026. space. It also raises questions for the reader as to whether the loss of
  5027. access to the object was intended or accidental.
  5028.  
  5029. An Ada environment is not required to provide deallocation of dynamically 
  5030. allocated objects. If provided, it may be provided implicitly (objects are 
  5031. deallocated when their access type goes out of scope), explicitly (objects are 
  5032. deallocated when Unchecked_Deallocation is called), or both. To increase the 
  5033. likelihood of the storage space being reclaimed, it is best to call 
  5034. Unchecked_Deallocation explicitly for each dynamically object when you are 
  5035. finished using it. Calls to Unchecked_Deallocation also document a deliberate 
  5036. decision to abandon an object, making the code easier to read and understand. 
  5037. To be absolutely certain that space is reclaimed and reused, manage your own 
  5038. "free list." Keep track of which objects you are finished with, and reuse them
  5039. instead of dynamically allocating new objects later.
  5040.  
  5041. The dangers of dangling references are that you may attempt to use them,
  5042. thereby accessing memory which you have released to the memory manager, and
  5043. which may have been subsequently allocated for another purpose in another part
  5044. of your program. When you read from such memory, unexpected errors may occur
  5045. because the other part of your program may have previously written totally
  5046. unrelated data there. Even worse, when you write to such memory you can cause
  5047. errors in an apparently unrelated part of the code by changing values of
  5048. variables dynamically allocated by that code. This type of error can be very
  5049. difficult to find. Finally, such errors may be triggered in parts of your
  5050. environment that you didn't write, for example, in the memory management
  5051. system itself which may dynamically allocate memory to keep records about your
  5052. dynamically allocated memory.
  5053.  
  5054. Keep in mind that any uninitialized or unreset component of a record or array 
  5055. can also be a dangling reference or carry a bit pattern representing 
  5056. inconsistent data. 
  5057.  
  5058. Whenever you use dynamic allocation it is possible to run out of space. Ada 
  5059. provides a facility (a length clause) for requesting the size of the pool of 
  5060. allocation space at compile time. Anticipate that you can still run out at run 
  5061. time. Prepare handlers for the exception Storage_Error, and consider carefully 
  5062. what alternatives you may be able to include in the program for each such 
  5063. situation.
  5064.  
  5065. There is a school of thought that dictates avoidance of all dynamic
  5066. allocation.  It is largely based on the fear of running out of memory during
  5067. execution.  Facilities such as length clauses and exception handlers for
  5068. Storage_Error provide explicit control over memory partitioning and error
  5069. recovery, making this fear unfounded.
  5070.  
  5071. 5.5     EXPRESSIONS
  5072.  
  5073. Properly coded expressions can enhance the readability and understandability
  5074. of a program. Poorly coded expressions can turn a program into a maintainer's
  5075. nightmare.
  5076.  
  5077. 5.5.1   Range Values
  5078.  
  5079. guideline
  5080.  
  5081. o       Use 'First or 'Last instead of numeric literals to represent the first 
  5082. or last values of a range.
  5083.  
  5084. o       Use the type or subtype name of the range instead of 'First .. 'Last.
  5085.  
  5086. example
  5087.  
  5088. type Temperature      is range All_Time_Low .. All_Time_High;
  5089. type Weather_Stations is range            1 ..  Max_Stations;
  5090.  
  5091. Current_Temperature : Temperature := 60;
  5092. Offset              : Temperature;
  5093.  
  5094. ...
  5095. for I in Weather_Stations loop
  5096.    Offset := Current_Temperature - Temperature'First;
  5097.  
  5098.    ...
  5099. end loop;
  5100.  
  5101. rationale
  5102.  
  5103. In the example above, it is better to use Weather_Stations in the for loop
  5104. than to use Weather_Stations'First .. Weather_Stations'Last or 1 ..
  5105. Max_Stations, because it is clearer, less error-prone, and less dependent on
  5106. the definition of the type Weather_Stations. Similarly, it is better to use
  5107. Temperature'First in the offset calculation than to use All_Time_Low, because
  5108. the code will still be correct if the definition of the subtype Temperature is
  5109. changed. This enhances program reliability.
  5110.  
  5111. caution
  5112.  
  5113. When you implicitly specify ranges and attributes like this, be careful that 
  5114. you use the correct type or subtype name. It is easy to refer to a very large 
  5115. range without realizing it. For example, given the declarations:
  5116.  
  5117. type    Large_Range is new Integer;
  5118. subtype Small_Range is Large_Range range 1 .. 10;
  5119.  
  5120. then the first declaration below works fine, but the second one is probably an 
  5121. accident and raises an exception on most machines because it is requesting a 
  5122. huge array (indexed from the smallest integer to the largest one):
  5123.  
  5124. Array_1 : array (Small_Range) of Integer;
  5125. Array_2 : array (Large_Range) of Integer;
  5126.  
  5127. 5.5.2   Array Attributes
  5128.  
  5129. guideline
  5130.  
  5131. o       Use array attributes 'First, 'Last, or 'Length instead of numeric 
  5132. literals for accessing arrays.
  5133.  
  5134. o     Use the 'Range of the array instead of the name of the index subtype
  5135. to express a range.
  5136.  
  5137. o       Use 'Range instead of 'First .. 'Last to express a range.
  5138.  
  5139. example
  5140.  
  5141. subtype Name_String is String (1 .. Name_Length);
  5142.  
  5143. File_Path : Name_String := (others => ' ');
  5144.  
  5145. ...
  5146.  
  5147. for I in File_Path'Range loop
  5148.    ...
  5149. end loop;
  5150.  
  5151. rationale
  5152.  
  5153. In the example above, it is better to use Name_String'Range in the for loop 
  5154. than to use Name_String_Size, Name_String'First .. Name_String'Last, or 1 .. 
  5155. 30, because it is clearer, less error-prone, and less dependent on the
  5156. definitions of Name_String and Name_String_Size. If Name_String is changed to 
  5157. have a different index type, or if the bounds of the array are changed, this 
  5158. will still work correctly. This enhances program reliability.
  5159.  
  5160. 5.5.3   Parenthetical Expressions
  5161.  
  5162. guideline
  5163.  
  5164. o       Use parentheses to specify the order of subexpression evaluation to 
  5165. clarify expressions (NASA 1987).
  5166.  
  5167. o       Use parentheses to specify the order of evaluation for subexpressions 
  5168. whose correctness depends on left to right evaluation.
  5169.  
  5170. example
  5171.  
  5172. (1.5 * X**2)/A - (6.5*X + 47.0)
  5173.  
  5174. 2*I + 4*Y + 8*Z + C
  5175.  
  5176. rationale
  5177.  
  5178. The Ada rules of operator precedence are defined in Section 4.5 of Department
  5179. of Defense (1983) and follow the same commonly accepted precedence of
  5180. algebraic operators.  The strong typing facility in Ada combined with the
  5181. common precedence rules make many parentheses unnecessary.  However, when an
  5182. uncommon combination of operators occurs, it may be helpful to add parentheses
  5183. even when the precedence rules apply.  The expression,
  5184.  
  5185. 5 + ((Y ** 3) mod 10)
  5186.  
  5187. is clearer, and equivalent to
  5188.  
  5189. 5 + Y**3 mod 10
  5190.  
  5191. The rules of evaluation do specify left to right evaluation for operators with
  5192. the same precedence level.  However, it is the most commonly overlooked rule
  5193. of evaluation when checking expressions for correctness.
  5194.  
  5195. 5.5.4   Positive Forms of Logic
  5196.  
  5197. guideline
  5198.  
  5199. o       Avoid names and constructs that rely on the use of negatives.
  5200.  
  5201. o       Choose names of flags so they represent states that can be used in 
  5202. positive form.
  5203.  
  5204. example
  5205.  
  5206. Use
  5207.  
  5208. if Operator_Missing then
  5209.  
  5210. rather than either
  5211.  
  5212. if not Operator_Found then
  5213.  
  5214. or
  5215.  
  5216. if not Operator_Missing then
  5217.  
  5218. rationale
  5219.  
  5220. Relational expressions can be more readable and understandable when stated in
  5221. a positive form. As an aid in choosing the name, consider that the most
  5222. frequently used branch in a conditional construct should be encountered first.
  5223.  
  5224. exception
  5225.  
  5226. There are cases in which the negative form is unavoidable. If the relational 
  5227. expression better reflects what is going on in the code, then inverting the 
  5228. test to adhere to this guideline is not recommended.
  5229.  
  5230. 5.5.5   Short Circuit Forms of the Logical Operators
  5231.  
  5232. guideline
  5233.  
  5234. o       Use short-circuit forms of the logical operators.
  5235.  
  5236. example
  5237.  
  5238. Use
  5239.  
  5240. if Y /= 0 or else (X/Y) /= 10 then
  5241.  
  5242. or
  5243.  
  5244. if Y /= 0 then
  5245.    if (X/Y) /= 10 then
  5246.  
  5247. rather than either
  5248.  
  5249. if Y /= 0 and (X/Y) /= 10 then
  5250.  
  5251. or to avoid Numeric_Error
  5252.  
  5253. if (X/Y) /= 10 then
  5254.  
  5255. Use
  5256.  
  5257. if Target /= null and then Target.Distance < Threshold then
  5258.  
  5259. rather than
  5260.  
  5261. if Target.Distance < Threshold then
  5262.  
  5263. to avoid referencing a field in a non-existent object.
  5264.  
  5265. rationale
  5266.  
  5267. The use of short-circuit control forms prevents a class of data-dependent
  5268. errors or exceptions that can occur as a result of expression evaluation. The 
  5269. short-circuit forms guarantee an order of evaluation and an exit from the
  5270. sequence of relational expressions as soon as the expression's result can be 
  5271. determined. 
  5272.  
  5273. In the absence of short-circuit forms, Ada does not provide a guarantee of the
  5274. order of expression evaluation, nor does the language guarantee that
  5275. evaluation of a relational expression is abandoned when it becomes clear that
  5276. it evaluates to False (for and) or True (for or).
  5277.  
  5278. note
  5279.  
  5280. If it is important that all parts of a given expression always be evaluated, 
  5281. the expression probably violates Guideline  which limits side-effects in
  5282. functions.
  5283.  
  5284. 5.5.6   Accuracy of Operations With Real Operands
  5285.  
  5286. guideline
  5287.  
  5288. o       Use <= and >= in relational expressions with real operands instead of 
  5289. =.
  5290.  
  5291. example
  5292.  
  5293. Current_Temperature   : Temperature :=       0.0;
  5294. Temperature_Increment : Temperature := 1.0 / 3.0;
  5295. Maximum_Temperature   : constant    :=     100.0;
  5296.  
  5297. ...
  5298. loop
  5299.  
  5300.    ...
  5301.    Current_Temperature :=
  5302.      Current_Temperature + Temperature_Increment;
  5303.  
  5304.    ...
  5305.    exit when Current_Temperature >= Maximum_Temperature;
  5306.  
  5307.    ...
  5308. end loop;
  5309.  
  5310. rationale
  5311.  
  5312. Fixed and floating point values, even if derived from similar expressions, may 
  5313. not be exactly equal. The imprecise, finite representations of real numbers in 
  5314. hardware always have round-off errors so that any variation in the construction
  5315. path or history of two reals has the potential for resulting in different 
  5316. numbers, even when the paths or histories are mathematically equivalent.
  5317.  
  5318. The Ada definition of model intervals also means that the use of <= is more 
  5319. portable than either < or =.
  5320.  
  5321. note
  5322.  
  5323. Floating point arithmetic is treated in Guideline .
  5324.  
  5325. exceptions
  5326.  
  5327. If your application must test for an exact value of a real number (e.g.,
  5328. testing the precision of the arithmetic on a certain machine), then the =
  5329. would have to be used. But never use = on real operands as a condition to exit
  5330. a loop.
  5331.  
  5332. 5.6     STATEMENTS
  5333.  
  5334. Careless or convoluted use of statements can make a program hard to read and
  5335. maintain even if its global structure is well organized. You should strive for
  5336. simple and consistent use of statements to achieve clarity of local program
  5337. structure. Some of the guidelines in this section counsel use or avoidance of
  5338. particular statements. As pointed out in the individual guidelines, rigid
  5339. adherence to those guidelines would be excessive, but experience has shown
  5340. that they generally lead to code with improved reliability and
  5341. maintainability.
  5342.  
  5343. 5.6.1   Nesting
  5344.  
  5345. guideline
  5346.  
  5347. o       Minimize the depth of nested expressions (Nissen and Wallis 1984).
  5348.  
  5349. o       Minimize the depth of nested control structures (Nissen and Wallis 
  5350. 1984).
  5351.  
  5352. o       Try simplification heuristics (see note).
  5353.  
  5354. instantiation
  5355.  
  5356. -    Do not nest expressions or control structures beyond a nesting level
  5357. of five.
  5358.  
  5359. example
  5360.  
  5361. The following section of code:
  5362.  
  5363. if not Condition_1 then
  5364.  
  5365.    if Condition_2 then
  5366.       Action_A;
  5367.    else  -- not Condition_2
  5368.       Action_B;
  5369.    end if;
  5370.  
  5371. else  -- Condition_1
  5372.    Action_C;
  5373. end if;
  5374.  
  5375. can be rewritten more clearly and with less nesting as:
  5376.  
  5377. if Condition_1 then
  5378.    Action_C;
  5379. elsif Condition_2 then
  5380.    Action_A;
  5381.  
  5382. else  -- not (Condition_1 or Condition_2)
  5383.    Action_B;
  5384. end if;
  5385.  
  5386. rationale
  5387.  
  5388. Deeply nested structures are confusing, difficult to understand, and difficult
  5389. to maintain. The problem lies in the difficulty of determining what part of a
  5390. program is contained at any given level. For expressions, this is important in
  5391. achieving the correct placement of balanced grouping symbols and in achieving
  5392. the desired operator precedence. For control structures, the question involves
  5393. what part is controlled. Specifically, is a given statement at the proper
  5394. level of nesting, i.e., is it too deeply or too shallowly nested, or is the
  5395. given statement associated with the proper choice, e.g., for if or case
  5396. statements?  Indentation helps, but it is not a panacea. Visually inspecting
  5397. alignment of indented code (mainly intermediate levels) is an uncertain job at
  5398. best. To minimize the complexity of the code, keep the maximum number of
  5399. nesting levels between three and five.
  5400.  
  5401. note
  5402.  
  5403. Ask yourself the following questions to help you simplify the code: 
  5404.  
  5405. -       Can some part of the expression be put into a constant or variable? 
  5406.  
  5407. -       Does some part of the lower nested control structures represent a 
  5408. significant, and perhaps reusable computation that I can factor into a 
  5409. subprogram? 
  5410.  
  5411. -       Can I convert these nested if statements into a case statement? 
  5412.  
  5413. -       Am I using else if where I could be using elsif? 
  5414.  
  5415. -       Can I reorder the conditional expressions controlling this nested 
  5416. structure? 
  5417.  
  5418. -       Is there a different design that would be simpler?
  5419.  
  5420. exceptions
  5421.  
  5422. If deep nesting is required frequently, there may be overall design decisions 
  5423. for the code that should be changed. Some algorithms require deeply nested 
  5424. loops and segments controlled by conditional branches. Their continued use can 
  5425. be ascribed to their efficiency, familiarity, and time proven utility. When 
  5426. nesting is required, proceed cautiously and take special care with the choice 
  5427. of identifiers and loop and block names. 
  5428.  
  5429. 5.6.2   Slices
  5430.  
  5431. guideline
  5432.  
  5433. o       Use slices rather than a loop to copy part of an array.
  5434.  
  5435. example
  5436.  
  5437. First  : constant Index := Index'First;
  5438. Second : constant Index := Index'Succ(First);
  5439. Third  : constant Index := Index'Succ(Second);
  5440.  
  5441. type Vector is array (Index range <>) of Element;
  5442.  
  5443. subtype Column_Vector is Vector (Index);
  5444. type    Square_Matrix is array  (Index) of Column_Vector;
  5445.  
  5446. subtype Small_Range  is Index range First .. Third;
  5447. subtype Diagonals    is Vector (Small_Range);
  5448. type    Tri_Diagonal is array  (Index) of Diagonals;
  5449.  
  5450. Markov_Probabilities : Square_Matrix;
  5451. Diagonal_Data        : Tri_Diagonal;
  5452.  
  5453. ...
  5454.  
  5455. -- Remove diagonal and off diagonal elements.
  5456. Diagonal_Data(Index'First)(First) := Null_Value;
  5457. Diagonal_Data(Index'First)(Second .. Third) :=
  5458.       Markov_Probabilities(Index'First)(First .. Second);
  5459.  
  5460. for I in Second .. Index'Pred(Index'Last) loop
  5461.    Diagonal_Data(I) :=
  5462.      Markov_Probabilities(I)(Index'Pred(I) .. Index'Succ(I));
  5463. end loop;
  5464.  
  5465. Diagonal_Data(Index'Last)(First .. Second) :=
  5466.       Markov_Probabilities(Index'Last)
  5467.      (Index'Pred(Index'Last) .. Index'Last);
  5468. Diagonal_Data(Index'Last)(Third) := Null_Value;
  5469.  
  5470. rationale
  5471.  
  5472. An assignment statement with slices is simpler and clearer than a loop, and
  5473. helps the reader see the intended action. Slice assignment can be faster than
  5474. a loop if a block move instruction is available.
  5475.  
  5476. 5.6.3   Case Statements
  5477.  
  5478. guideline
  5479.  
  5480. o       Never use an others choice in a case statement.
  5481.  
  5482. o       Do not use ranges of enumeration literals in case statements.
  5483.  
  5484. example
  5485.  
  5486. type Color is (Red, Green, Blue, Purple);
  5487. Car_Color : Color := Red;
  5488.  
  5489. ...
  5490.  
  5491. case Car_Color is
  5492.    when Red .. Blue => ...
  5493.    when Purple      => ...
  5494. end case;  -- Car_Color
  5495.  
  5496. Now consider a change in the type:
  5497.  
  5498. type Color is (Red, Yellow, Green, Blue, Purple);
  5499.  
  5500. This change may have an unnoticed and undesired effect in the case statement. 
  5501. If the choices had been enumerated explicitly, as when Red | Green | Blue => 
  5502. instead of when Red .. Blue =>, then the case statement would have not have 
  5503. compiled. This would have forced the maintainer to make a conscious decision 
  5504. about what to do in the case of Yellow.
  5505.  
  5506. rationale
  5507.  
  5508. All possible values for an object should be known and should be assigned 
  5509. specific actions. Use of an others clause may prevent the developer from 
  5510. carefully considering the actions for each value. A compiler warns the user 
  5511. about omitted values, if an others clause is not used.  
  5512.  
  5513. Each possible value should be explicitly enumerated. Ranges can be dangerous 
  5514. because of the possibility that the range could change and the case statement 
  5515. may not be reexamined.
  5516.  
  5517. exception
  5518.  
  5519. It is acceptable to use ranges for possible values only when the user is 
  5520. certain that new values will never be inserted among the old ones, as for 
  5521. example, in the range of ASCII characters: 'a' .. 'z'.
  5522.  
  5523. note
  5524.  
  5525. Ranges that are needed in case statements can use constrained subtypes to 
  5526. enhance maintainability.  It is easier to maintain because the declaration of 
  5527. the range can be placed where it is logically part of the abstraction, not 
  5528. buried in a case statement in the executable code.
  5529.  
  5530. subtype Lower_Case is Character range       'a' ..      'z';
  5531. subtype Upper_Case is Character range       'A' ..      'Z';
  5532. subtype Control    is Character range ASCII.Nul .. ASCII.Us;
  5533. subtype Numbers    is Character range       '0' ..      '9';
  5534.  
  5535. ...
  5536. case Input_Char is
  5537.    when Lower_Case =>         Capitalize(Input_Char);
  5538.    when Upper_Case =>         null;
  5539.    when Control    =>         raise Invalid_Input;
  5540.    when Numbers    =>         null;
  5541.    ...
  5542. end case;
  5543.  
  5544. 5.6.4   Loops
  5545.  
  5546. guideline
  5547.  
  5548. o       Use for loops whenever possible.
  5549.  
  5550. o    Use while loops when the number of iterations cannot be calculated
  5551. before entering the loop, but a simple continuation condition can be applied
  5552. at the top of the loop.
  5553.  
  5554. o       Use plain loops with exit statements for more complex situations.
  5555.  
  5556. o       Avoid exit statements in while and for loops.
  5557.  
  5558. o       Minimize the number of ways to exit a loop.
  5559.  
  5560. example
  5561.  
  5562. To iterate over all elements of an array:
  5563.  
  5564. for 1 in Array_Name'Range loop
  5565.    ...
  5566. end loop;
  5567.  
  5568. To iterate over all elements in a linked list:
  5569.  
  5570. Pointer := Head_Of_List;
  5571. while Pointer /= null loop
  5572.    ...
  5573.    Pointer := Pointer.Next;
  5574. end loop;
  5575.  
  5576. Situations requiring a "loop and a half" arise often. For this use:
  5577.  
  5578. P_And_Q_Processing:
  5579.    loop
  5580.       P;
  5581.       exit P_And_Q_Processing when Condition_Dependent_On_P;
  5582.       Q;
  5583.    end loop P_And_Q_Processing;
  5584.  
  5585. rather than:
  5586.  
  5587. P;
  5588. while not Condition_Dependent_On_P loop
  5589.    Q;
  5590.    P;
  5591. end loop;
  5592.  
  5593. rationale
  5594.  
  5595. A for loop is bounded, so it cannot be an "infinite loop." This is enforced by
  5596. the Ada language which requires a finite range in the loop specification and
  5597. which does not allow the loop counter of a for loop to be modified by a
  5598. statement executed within the loop. This yields a certainty of understanding
  5599. for the reader and the writer not associated with other forms of loops. A for
  5600. loop is also easier to maintain because the iteration range can be expressed
  5601. using attributes of the data structures upon which the loop operates, as shown
  5602. in the example above where the range changes automatically whenever the
  5603. declaration of the array is modified. For these reasons, it is best to use the
  5604. for loop whenever possible; that is, whenever simple expressions can be used
  5605. to describe the first and last values of the loop counter.
  5606.  
  5607. The while loop has become a very familiar construct to most programmers. At a
  5608. glance it indicates the condition under which the loop continues. Use the
  5609. while loop whenever it is not possible to use the for loop, but there is a
  5610. simple boolean expression describing the conditions under which the loop
  5611. should continue, as shown in the example above.
  5612.  
  5613. The plain loop statement should be used in more complex situations, even if it 
  5614. is possible to contrive a solution using a for or while loop in conjunction 
  5615. with extra flag variables or exit statements. The criteria in selecting a loop 
  5616. construct is to be as clear and maintainable as possible. It is a bad idea to 
  5617. use an exit statement from within a for or while loop because it is misleading 
  5618. to the reader after having apparently described the complete set of loop 
  5619. conditions at the top of the loop. A reader who encounters a plain loop 
  5620. statement expects to see exit statements.
  5621.  
  5622. There are some familiar looping situations which are best achieved with the
  5623. plain loop statement. For example, the semantics of the Pascal repeat until
  5624. loop, where the loop is always executed at least once before the termination
  5625. test occurs, are best achieved by a plain loop with a single exit at the end
  5626. of the loop. Another common situation is the "loop and a half" construct,
  5627. shown in the example above, where a loop must terminate somewhere within the
  5628. sequence of statements of the body. Complicated "loop and a half" constructs
  5629. simulated with while loops often require the introduction of flag variables,
  5630. or duplication of code before and during the loop, as shown in the example.
  5631. Such contortions make the code more complex and less reliable.
  5632.  
  5633. Minimize the number of ways to exit a loop in order to make the loop more 
  5634. understandable to the reader. It should be rare that you need more than two 
  5635. exit paths from a loop. When you do, be sure to use exit statements for all of 
  5636. them, rather than adding an exit statement to a for or while loop.
  5637.  
  5638. 5.6.5   Exit Statements
  5639.  
  5640. guideline
  5641.  
  5642. o    Use exit statements to enhance the readability of loop termination
  5643. code (NASA 1987).
  5644.  
  5645. o       Use exit when ... rather than if ... then exit whenever possible (NASA 
  5646. 1987).
  5647.  
  5648. o       Review exit statement placement.
  5649.  
  5650. example
  5651.  
  5652. See the examples in Guidelines  and .
  5653.  
  5654. rationale
  5655.  
  5656. It is more readable to use exit statements than to try to add boolean flags to
  5657. a while loop condition to simulate exits from the middle of a loop. Even if
  5658. all exit statements would be clustered at the top of the loop body, the
  5659. separation of a complex condition into multiple exit statements can simplify
  5660. and make it more readable and clear. The sequential execution of two exit
  5661. statements is often more clear than the short-circuit control forms.
  5662.  
  5663. The exit when form is preferable to the if ... then, exit form because it
  5664. makes the word exit more visible by not nesting it inside of any control
  5665. construct.  The if ... then exit form is needed only in the case where other
  5666. statements, in addition to the exit statement, must be executed conditionally.
  5667. For example:
  5668.  
  5669. if Status = Done then
  5670.  
  5671.    Shut_Down;
  5672.    return;
  5673.  
  5674. end if;
  5675.  
  5676. Loops with many scattered exit statements can indicate fuzzy thinking as 
  5677. regards the loop's purpose in the algorithm. Such an algorithm might be coded 
  5678. better some other way, e.g., with a series of loops. Some rework can often 
  5679. reduce the number of exit statements and make the code clearer.
  5680.  
  5681. See also Guidelines  and .
  5682.  
  5683. 5.6.6   Recursion and Iteration Bounds
  5684.  
  5685. guideline
  5686.  
  5687. o       Consider specifying bounds on loops.
  5688.  
  5689. o       Consider specifying bounds on recursion.
  5690.  
  5691. example
  5692.  
  5693. Establishing an iteration bound:
  5694.  
  5695. Safety_Counter := 0;
  5696.  
  5697. Process_List:
  5698.    loop
  5699.       exit when Current_Item = null;
  5700.  
  5701.       ...
  5702.       Current_Item := Current_Item.Next;
  5703.  
  5704.       ...
  5705.       Safety_Counter := Safety_Counter + 1;
  5706.       if Safety_Counter > 1_000_000 then
  5707.      raise Safety_Error;
  5708.       end if;
  5709.  
  5710.    end loop Process_List;
  5711.  
  5712. Establishing a recursion bound:
  5713.  
  5714. procedure Depth_First (Root           : in     Tree;
  5715.                Safety_Counter : in     Recursion_Bound
  5716.                       := Recursion_Bound'Last) is
  5717. begin
  5718.    if Root /= null then
  5719.  
  5720.       if Safety_Counter = 0 then
  5721.      raise Recursion_Error;
  5722.       end if;
  5723.  
  5724.       Depth_First
  5725.        (Root.Left_Branch,   Safety_Counter - 1); -- recursivecall
  5726.       Depth_First
  5727.        (Root.Right_Branch,  Safety_Counter - 1); -- recursivecall
  5728.  
  5729.       ... -- normal subprogram body
  5730.    end if;
  5731.  
  5732. end Depth_First;
  5733.  
  5734. Following are examples of this subprogram's usage. One call specifies a
  5735. maximum recursion depth of 50. The second takes the default (one thousand).
  5736. The third uses a computed bound:
  5737.  
  5738. Depth_First(Root, 50);
  5739. Depth_First(Root);
  5740. Depth_First(Root, Current_Tree_Height);
  5741.  
  5742. rationale
  5743.  
  5744. Recursion, and iteration using structures other than for statements, can be
  5745. infinite because the expected terminating condition does not arise. Such
  5746. faults are sometimes quite subtle, may occur rarely, and may be difficult to
  5747. detect because an external manifestation might be absent or substantially
  5748. delayed.
  5749.  
  5750. By including counters and checks on the counter values, in addition to the
  5751. loops themselves, you can prevent many forms of infinite loops. The inclusion
  5752. of such checks is one aspect of the technique called Safe Programming
  5753. (Anderson and Witty 1978).
  5754.  
  5755. The bounds of these checks do not have to be exact, just realistic. Such
  5756. counters and checks are not part of the primary control structure of the
  5757. program but a benign addition functioning as an execution-time "safety net"
  5758. allowing error detection and possibly recovery from potential infinite loops
  5759. or infinite recursion.
  5760.  
  5761. note
  5762.  
  5763. If a loop uses the for iteration scheme (Guideline ), it follows this 
  5764. guideline.
  5765.  
  5766. exceptions
  5767.  
  5768. Embedded control applications have loops that are intended to be infinite.
  5769. Only a few loops within such applications should qualify as exceptions to this
  5770. guideline. The exceptions should be deliberate (and documented) policy
  5771. decisions.
  5772.  
  5773. This guideline is most important to safety critical systems. For other
  5774. systems, it may be overkill.
  5775.  
  5776. 5.6.7   Goto Statements
  5777.  
  5778. guideline
  5779.  
  5780. o       Do not use goto statements.
  5781.  
  5782. rationale
  5783.  
  5784. A goto statement is an unstructured change in the control flow. Worse, the 
  5785. label does not require an indicator of where the corresponding goto 
  5786. statement(s) are. This makes code unreadable and makes its correct execution 
  5787. suspect. 
  5788.  
  5789. Other languages use goto statements to implement loop exits and exception
  5790. handling.  Ada's support of these constructs makes the goto statement
  5791. extremely rare.
  5792.  
  5793. note
  5794.  
  5795. If you should ever use a goto statement, highlight both it and the label with 
  5796. blank space. Indicate at the label where the corresponding goto statement(s) 
  5797. may be found.
  5798.  
  5799. 5.6.8   Return Statements
  5800.  
  5801. guideline
  5802.  
  5803. o       Minimize the number of returns from a subprogram (NASA 1987).
  5804.  
  5805. o       Highlight returns with comments or white space to keep them from being 
  5806. lost in other code. 
  5807.  
  5808. example
  5809.  
  5810. The following code fragment is longer and more complex than necessary:
  5811.  
  5812. if Pointer /= null then
  5813.  
  5814.    if Pointer.Count > 0 then
  5815.       return True;
  5816.  
  5817.    else  -- Pointer.Count = 0
  5818.       return False;
  5819.    end if;
  5820.  
  5821. else  -- Pointer = null
  5822.    return False;
  5823. end if;
  5824.  
  5825. It should be replaced with the shorter, more concise, and clearer equivalent 
  5826. line:
  5827.  
  5828. return Pointer /= null and then Pointer.Count > 0;
  5829.  
  5830. rationale
  5831.  
  5832. Excessive use of returns can make code confusing and unreadable. Only use
  5833. return statements where warranted. Too many returns from a subprogram may be
  5834. an indicator of cluttered logic. If the application requires multiple returns,
  5835. use them at the same level (i.e., as in different branches of a case
  5836. statement), rather than scattered throughout the subprogram code. Some rework
  5837. can often reduce the number of return statements to one and make the code more
  5838. clear.
  5839.  
  5840. exception
  5841.  
  5842. Do not avoid return statements if it detracts from natural structure and code 
  5843. readability. 
  5844.  
  5845. 5.6.9   Blocks
  5846.  
  5847. guideline
  5848.  
  5849. o       Use blocks to localize the scope of declarations.
  5850.  
  5851. o       Use blocks to perform local renaming.
  5852.  
  5853. o       Use blocks to define local exception handlers.
  5854.  
  5855. example
  5856.  
  5857. with Motion;
  5858. with Accelerometer_Device;
  5859. ...
  5860.  
  5861.    ---------------------------------------------------------------------
  5862.    function Maximum_Velocity return Motion.Velocity is
  5863.  
  5864.       Cumulative : Motion.Velocity := 0.0;
  5865.  
  5866.    begin  -- Maximum_Velocity
  5867.  
  5868.       -- Initialize the needed devices
  5869.       ...
  5870.  
  5871.       Calculate_Velocity_From_Sample_Data:
  5872.      declare
  5873.         Current       : Motion.Acceleration := 0.0;
  5874.         Accelerometer : Accelerometer_Device.Interface;
  5875.         Time_Delta    : Duration;
  5876.  
  5877.      begin  -- Calculate_Velocity_From_Sample_Data
  5878.         for I in 1 .. Accelerometer_Device.Sample_Limit loop
  5879.  
  5880.            Get_Samples_And_Ignore_Invalid_Data:
  5881.           begin
  5882.              Accelerometer.Value(Current, Time_Delta);
  5883.           exception
  5884.              when Numeric_Error | Constraint_Error =>
  5885.             null; -- Continue trying
  5886.  
  5887.              when Accelerometer_Device.Failure =>
  5888.             raise Accelerometer_Device_Failed;
  5889.           end Get_Samples_And_Ignore_Invalid_Data;
  5890.  
  5891.            exit when Motion."<"(Current, 0.0); -- Slowing down
  5892.  
  5893.            Update_Velocity:
  5894.           declare
  5895.              use Motion; -- for infix operators and exceptions;
  5896.  
  5897.           begin
  5898.              Cumulative := Cumulative + Current * Time_Delta;
  5899.  
  5900.           exception
  5901.              when Numeric_Error | Constraint_Error =>
  5902.             raise Maximum_Velocity_Exceeded;
  5903.           end Update_Velocity;
  5904.  
  5905.         end loop;
  5906.      end Calculate_Velocity_From_Sample_Data;
  5907.  
  5908.       return Cumulative;
  5909.  
  5910.    end Maximum_Velocity;
  5911.    ---------------------------------------------------------------------
  5912. ...
  5913.  
  5914. rationale
  5915.  
  5916. Blocks break up large segments of code and isolate details relevant to each 
  5917. subsection of code.  Variables that are only used in a particular section of 
  5918. code are clearly visible when a declarative block delineates that code.
  5919.  
  5920. Renaming may simplify the expression of algorithms and enhance readability for
  5921. a given section of code.  But it is confusing when a rename clause is visually
  5922. separated from the code to which it applies.  The declarative region allows
  5923. the renames to be immediately visible when the reader is examining code which
  5924. uses that abbreviation.  Guideline 5.7.1 discusses a similar guideline
  5925. concerning the `use' clause.
  5926.  
  5927. Local exception handlers can catch exceptions close to the point of origin and 
  5928. allow them to either be handled, propogated, or converted.
  5929.  
  5930. 5.6.10  Aggregates
  5931.  
  5932. guideline
  5933.  
  5934. o       Use an aggregate instead of a sequence of assignments to assign values 
  5935. to all components of a record.
  5936.  
  5937. o    Use an aggregate instead of a temporary variable when building a
  5938. record to pass as an actual parameter.
  5939.  
  5940. o       Use positional association only when there is a conventional ordering 
  5941. of the arguments.
  5942.  
  5943. example
  5944.  
  5945. It is better to use aggregates:
  5946.  
  5947. Set_Position((X, Y));
  5948.  
  5949. Employee_Record :=  (Number     => 42,
  5950.              Age        => 51,
  5951.              Department => Software_Engineering);
  5952.  
  5953. than to use consecutive assignments or temporary variables:
  5954.  
  5955. Temporary_Position.X := 100;
  5956. Temporary_Position.Y := 200;
  5957. Set_Position(Temporary_Position);
  5958.  
  5959. Employee_Record.Number     := 42;
  5960. Employee_Record.Age        := 51;
  5961. Employee_Record.Department := Software_Engineering;
  5962.  
  5963. rationale
  5964.  
  5965. Using aggregates during maintenance is beneficial. If a record structure is
  5966. altered, but the corresponding aggregate is not, the compiler flags the
  5967. missing field in the aggregate assignment. It would not be able to detect the
  5968. fact that a new assignment statement should have been added to a list of
  5969. assignment statements.
  5970.  
  5971. Aggregates can also be a real convenience in combining data items into a
  5972. record or array structure required for passing the information as a parameter.
  5973. Named component association makes aggregates more readable.
  5974.  
  5975. 5.7     VISIBILITY
  5976.  
  5977. As noted in Guideline 4.2, Ada's ability to enforce information hiding and 
  5978. separation of concerns through its visibility controlling features is one of 
  5979. the most important advantages of the language. Subverting these features, for 
  5980. example by over liberal use of the use clause, is wasteful and dangerous. 
  5981.  
  5982. 5.7.1   The Use Clause
  5983.  
  5984. guideline
  5985.  
  5986. o       Minimize using the use clause (Nissen and Wallis 1984).
  5987.  
  5988. o       Consider using the use clause in the following situations:
  5989.  
  5990. -       Infix operators are needed
  5991.  
  5992. -       Standard packages are needed and no ambiguous references are introduced
  5993.  
  5994. -       References to enumeration literals are needed
  5995.  
  5996. o       Consider the renames clause to avoid the use clause.
  5997.  
  5998. o       Localize the effect of all use clauses.
  5999.  
  6000. example
  6001.  
  6002. This is a modification of the example from Guideline . The effect of a use 
  6003. clause is localized.
  6004.  
  6005. ...
  6006. procedure Compiler is
  6007.  
  6008.    ...
  6009.    package Listing_Facilities is
  6010.    end Listing_Facilities;
  6011.  
  6012.    ...
  6013.    package body Listing_Facilities is separate;
  6014.  
  6015.    ...
  6016. end Compiler;
  6017.  
  6018. ------------------------------------------------------------------------
  6019. with Text_IO;
  6020.  
  6021. separate (Compiler)
  6022. package body Listing_Facilities is
  6023.  
  6024.    ...
  6025.  
  6026.    ---------------------------------------------------------------------
  6027.    procedure New_Line_Of_Print is
  6028.       use Text_IO;
  6029.    begin
  6030.       ...
  6031.    end New_Line_Of_Print;
  6032.  
  6033.    ...
  6034. end Listing_Facilities;
  6035.  
  6036. rationale
  6037.  
  6038. These guidelines allow you to maintain a careful balance between
  6039. maintainability and readability.  Excessive use of the use clause may indeed
  6040. make the code read more like prose text.  However, the maintainer may also
  6041. need to resolve references and identify ambiguous operations.  In the absence
  6042. of tools to resolve these references and identify the impact of changing use
  6043. clauses, fully qualified names are the best alternative.
  6044.  
  6045. Avoiding the use clause forces you to use fully qualified names. In large 
  6046. systems, there may be many library units named in with clauses. When 
  6047. corresponding use clauses accompany the with clauses and the simple names of 
  6048. the library packages are omitted (as is allowed by the use clause), references 
  6049. to external entities are obscured and identification of external dependencies 
  6050. becomes difficult. 
  6051.  
  6052. In some situations, the benefits of the use clause are clear.  The use clause
  6053. can make several infix operators visible without the need for renames clauses.
  6054. A standard package can be used with the obvious assumption that the reader is
  6055. very familiar with those packages and that additional overloading will not be
  6056. introduced.
  6057.  
  6058. You can minimize the scope of the use clause by placing it in the body of a 
  6059. package or subprogram or by encapsulating it in a block to restrict visibility.
  6060.  
  6061. notes
  6062.  
  6063. Avoiding the use clause completely can cause problems with enumeration 
  6064. literals, which must then be fully qualified. This problem can be solved by 
  6065. declaring constants with the enumeration literals as their values, except that 
  6066. such constants cannot be overloaded like enumeration literals.
  6067.  
  6068. An argument defending the use clause can be found in Rosen (1987).
  6069.  
  6070. automation note
  6071.  
  6072. There are tools that can analyze your Ada source code, resolve overloading of 
  6073. names, and automatically convert between the use clause or fully qualified 
  6074. names.
  6075.  
  6076. 5.7.2   The Renames Clause
  6077.  
  6078. guideline
  6079.  
  6080. o       Rename a long, fully qualified name to reduce the complexity if it 
  6081. becomes unwieldy (Guideline ).
  6082.  
  6083. o       Rename declarations for visibility purposes rather than using the use 
  6084. clause, especially for infix operators (Guideline ).
  6085.  
  6086. o    Rename parts when interfacing to reusable components originally
  6087. written with nondescriptive or inapplicable nomenclature.
  6088.  
  6089. o       Use a project-wide standard list of abbreviations to rename common
  6090. packages.
  6091.  
  6092. example
  6093.  
  6094. procedure Disk_Write (Track_Name : in     Track;
  6095.               Item       : in     Data) renames
  6096.    System_Specific.Device_Drivers.Disk_Head_Scheduler.Transmit;
  6097.  
  6098. rationale
  6099.  
  6100. If the renaming facility is abused, the code can be difficult to read. A
  6101. renames clause can substitute an abbreviation for a qualifier or long package
  6102. name locally. This can make code more readable yet anchor the code to the full
  6103. name. However, the use of renames clauses can often be avoided or made
  6104. obviously undesirable by carefully choosing names so that fully qualified
  6105. names read well. The list of renaming declarations serves as a list of
  6106. abbreviation definitions (see Guideline ). By renaming imported infix
  6107. operators, the use clause can often be avoided. The method prescribed in the
  6108. Ada Language Reference Manual (Department of Defense 1983) for renaming a type
  6109. is to use a subtype (see Guideline ). Often the parts recalled from a reuse
  6110. library do not have names that are as general as they could be or that match
  6111. the new application's naming scheme. An interface package exporting the
  6112. renamed subprograms can map to your project's nomenclature.
  6113.  
  6114. 5.7.3   Overloaded Subprograms
  6115.  
  6116. guideline
  6117.  
  6118. o       Limit overloading to widely used subprograms that perform similar 
  6119. actions on arguments of different types (Nissen and Wallis 1984).
  6120.  
  6121. example
  6122.  
  6123. function Sin (Angles : in     Matrix_Of_Radians) return Matrix;
  6124. function Sin (Angles : in     Vector_Of_Radians) return Vector;
  6125. function Sin (Angle  : in     Radians)           return Small_Real;
  6126. function Sin (Angle  : in     Degrees)           return Small_Real;
  6127.  
  6128. rationale
  6129.  
  6130. Excessive overloading can be confusing to maintainers (Nissen and Wallis 1984,
  6131. 65). There is also the danger of hiding declarations if overloading becomes
  6132. habitual.  Attempts to overload an operation may actually hide the original
  6133. operation if the parameter profile is not distinct.  From that point on, it is
  6134. not clear whether invoking the new operation is what the programmer intended
  6135. or whether the programmer intended to invoke the hidden operation and
  6136. accidentally hid it.
  6137.  
  6138. note
  6139.  
  6140. This guideline does not prohibit subprograms with identical names declared in 
  6141. different packages.
  6142.  
  6143. 5.7.4   Overloaded Operators
  6144.  
  6145. guideline
  6146.  
  6147. o       Preserve the conventional meaning of overloaded operators (Nissen and 
  6148. Wallis 1984).
  6149.  
  6150. o       Use "+" to identify adding, joining, increasing, and enhancing kinds of
  6151. functions. 
  6152.  
  6153. o       Use "-" to identify subtraction, separation, decreasing, and depleting
  6154. kinds of functions.
  6155.  
  6156. example
  6157.  
  6158. function "+" (X : in     Matrix;
  6159.           Y : in     Matrix)
  6160.       return Matrix;
  6161.  
  6162. ...
  6163. Sum := A + B;
  6164.  
  6165. rationale
  6166.  
  6167. Subverting the conventional interpretation of operators leads to confusing 
  6168. code.
  6169.  
  6170. note
  6171.  
  6172. There are potential problems with any overloading. For example, if there are 
  6173. several versions of the "+" operator, and a change to one of them affects the
  6174. number or order of its parameters, locating the occurrences that must be 
  6175. changed can be difficult.
  6176.  
  6177. 5.7.5   Overloading the Equality Operator
  6178.  
  6179. guideline
  6180.  
  6181. o       Do not depend on the definition of equality provided by private types.
  6182.  
  6183. o       When overloading the equality operator for limited private types, 
  6184. maintain the properties of an algebraic equivalence relation.
  6185.  
  6186. rationale
  6187.  
  6188. The predefined equality operation provided with private types is dependent on
  6189. the data structure chosen to implement that type.  If access types are used,
  6190. then equality will mean the operands have the same pointer value.  If discrete
  6191. types are used, then equality will mean the operands have the same value.  If
  6192. a floating point type is used, then equality is based on Ada model intervals
  6193. (see Guideline .).
  6194.  
  6195. Any assumptions about the meaning of equality for private types will create a 
  6196. dependency on the implementation of that type.  See Gonzalez (1992) for a 
  6197. detailed discussion.
  6198.  
  6199. For limited private types, the definition of "=" is optional.  When provided, 
  6200. however, there is a conventional algebraic meaning implied by this symbol.  As 
  6201. described in Baker (1991), the following properties should remain true for the 
  6202. equality operator:
  6203.  
  6204. -       reflexive:      a = a
  6205.  
  6206. -       symmetric:      a = b ==> b = a
  6207.  
  6208. -       transitive:     a = b and b = c  ==> a = c
  6209.  
  6210. 5.8     USING EXCEPTIONS
  6211.  
  6212. Ada exceptions are a reliability-enhancing language feature designed to help
  6213. specify program behavior in the presence of errors or unexpected events. 
  6214. Exceptions are not intended to provide a general purpose control construct. 
  6215. Further, liberal use of exceptions should not be considered sufficient for 
  6216. providing full software fault tolerance (Melliar-Smith and Randall 1987).
  6217.  
  6218. This section addresses the issues of how and when to avoid raising exceptions,
  6219. how and where to handle them, and whether to propagate them. Information on
  6220. how to use exceptions as part of the interface to a unit include what
  6221. exceptions to declare and raise and under what conditions to raise them.
  6222. Other issues are addressed in Guidelines and .
  6223.  
  6224. 5.8.1   Handling Versus Avoiding Exceptions
  6225.  
  6226. guideline
  6227.  
  6228. o       Avoid causing exceptions to be raised when it is easy and efficient to 
  6229. do so.
  6230.  
  6231. o       Provide handlers for exceptions which cannot be avoided.
  6232.  
  6233. o       Use exception handlers to enhance readability by separating fault 
  6234. handling from normal execution.
  6235.  
  6236. o       Do not use exceptions and exception handlers as goto statements.
  6237.  
  6238. rationale
  6239.  
  6240. In many cases, it is possible to detect easily and efficiently that an
  6241. operation you are about to perform would raise an exception. In such a case,
  6242. it is a good idea to check rather than allowing the exception to be raised and
  6243. handling it with an exception handler. For example, check each pointer for
  6244. NULL when traversing a linked list of records connected by pointers. Also,
  6245. test an integer for zero before dividing by it, and call an interrogative
  6246. function Stack_Is_Empty before invoking the POP procedure of a stack package.
  6247. Such tests are appropriate when they can be performed easily and efficiently,
  6248. as a natural part of the algorithm being implemented.
  6249.  
  6250. However, error detection in advance is not always so simple. There are cases
  6251. where such a test is too expensive or too unreliable. In such cases, it is
  6252. better to attempt the operation within the scope of an exception handler so
  6253. that the exception is handled if it is raised. For example, in the case of a
  6254. linked list implementation of a list, it is very inefficient to call a
  6255. function Entry_Exists before each call to the procedure Modify_Entry simply to
  6256. avoid raising the exception Entry_Not_Found. It takes as much time to search
  6257. the list to avoid the exception as it takes to search the list to perform the
  6258. update.  Similarly, it is much easier to attempt a division by a real number
  6259. within the scope of an exception handler to handle numeric overflow than to
  6260. test in advance whether the dividend is too large or the divisor too small for
  6261. the quotient to be representable on the machine.
  6262.  
  6263. In concurrent situations, tests done in advance can also be unreliable. For
  6264. example, if you want to modify an existing file on a multi-user system, it is
  6265. safer to attempt to do so within the scope of an exception handler than to
  6266. test in advance whether the file exists, whether it is protected, whether
  6267. there is room in the file system for the file to be enlarged, etc. Even if you
  6268. tested for all possible errors conditions, there is no guarantee that nothing
  6269. would change after the test and before the modification operation. You still
  6270. need the exception handlers, so the advance testing serves no purpose.
  6271.  
  6272. Whenever such a case does not apply, normal and predictable events should be 
  6273. handled by the code without the abnormal transfer of control represented by an 
  6274. exception. When fault handling and only fault handling code is included in 
  6275. exception handlers, the separation makes the code easier to read. The reader 
  6276. can skip all the exception handlers and still understand the normal flow of 
  6277. control of the code. For this reason, exceptions should never be raised and 
  6278. handled within the same unit, as a form of a goto statement to exit from a 
  6279. loop, if, case, or block statement.
  6280.  
  6281. 5.8.2   Handlers for others
  6282.  
  6283. guideline
  6284.  
  6285. o       Use caution when programming handlers for others.
  6286.  
  6287. o       Provide a handler for others in suitable frames to protect against 
  6288. unexpected exceptions being propagated without bound, especially in safety 
  6289. critical systems.
  6290.  
  6291. o       Use others only to catch exceptions you cannot enumerate explicitly, 
  6292. preferably only to flag a potential abort.
  6293.  
  6294. o       Avoid using others during development.
  6295.  
  6296. rationale
  6297.  
  6298. Providing a handler for others allows you to follow the other guidelines in
  6299. this section. It affords a place to catch and convert truly unexpected
  6300. exceptions that were not caught by the explicit handlers. While it may be
  6301. possible to provide "fire walls" against unexpected exceptions being
  6302. propagated without providing handlers in every block, you can convert the
  6303. unexpected exceptions as soon as they arise. The others handler cannot
  6304. discriminate between different exceptions, and, as a result, any such handler
  6305. must treat the exception as a disaster. Even such a disaster can still be
  6306. converted into a user-defined exception at that point. Since a handler for
  6307. others catches any exception not otherwise handled explicitly, one placed in
  6308. the frame of a task or of the main subprogram affords the opportunity to
  6309. perform final clean-up and to shut down cleanly.
  6310.  
  6311. Programming a handler for others requires caution because it cannot 
  6312. discriminate either which exception was actually raised or precisely where it 
  6313. was raised. Thus, the handler cannot make any assumptions about what can be or 
  6314. even what needs to be "fixed."
  6315.  
  6316. The use of handlers for others during development, when exception occurrences 
  6317. can be expected to be frequent, can hinder debugging. It is much more 
  6318. informative to the developer to see a traceback with the actual exception 
  6319. listed than the converted exception. Furthermore, many tracebacks do not list 
  6320. the point where the original exception was raised if it was caught by a 
  6321. handler.
  6322.  
  6323. note
  6324.  
  6325. The arguments in the preceding paragraph apply only to development time, when 
  6326. traceback listings are useful. They are not useful to users and can be 
  6327. dangerous. The handler should be included in comment form at the outset of 
  6328. development and the double dash removed before delivery.
  6329.  
  6330. 5.8.3   Propagation
  6331.  
  6332. guideline
  6333.  
  6334. o       Handle all exceptions, both user and predefined.
  6335.  
  6336. o    For every exception that might be raised, provide a handler in
  6337. suitable frames to protect against undesired propagation outside the
  6338. abstraction.
  6339.  
  6340. rationale
  6341.  
  6342. The statement that "it can never happen" is not an acceptable programming
  6343. approach. You must assume it can happen and be in control when it does. You 
  6344. should provide defensive code routines for the "cannot get here" conditions.
  6345.  
  6346. Some existing advice calls for catching and propagating any exception to the 
  6347. calling unit. This advice can stop a program. You should catch the exception 
  6348. and propagate it, or a substitute, only if your handler is at the wrong 
  6349. abstraction level to effect recovery. Effecting recovery can be difficult, but 
  6350. the alternative is a program that does not meet its specification.
  6351.  
  6352. Making an explicit request for termination implies that your code is in
  6353. control of the situation and has determined that to be the only safe course of
  6354. action.  Being in control affords opportunities to shut down in a controlled
  6355. manner (clean up loose ends, close files, release surfaces to manual control,
  6356. sound alarms), and implies that all available programmed attempts at recovery
  6357. have been made.
  6358.  
  6359. 5.8.4   Localizing the Cause of an Exception
  6360.  
  6361. guideline
  6362.  
  6363. o       Do not rely on being able to identify the fault raising predefined or 
  6364. implementation-defined exceptions.
  6365.  
  6366. o       Use blocks to associate localized sections of code with their own 
  6367. exception handlers.
  6368.  
  6369. example
  6370.  
  6371. See Guideline .
  6372.  
  6373. rationale
  6374.  
  6375. It is very difficult to determine in an exception handler exactly which 
  6376. statement and which operation within that statement raised an exception, 
  6377. particularly the predefined and implementation-defined exceptions. The
  6378. predefined and implementation-defined exceptions are candidates for conversion
  6379. and propagation to higher abstraction levels for handling there. User-defined
  6380. exceptions, being more closely associated with the application, are better 
  6381. candidates for recovery within handlers.
  6382.  
  6383. User-defined exceptions can also be difficult to localize. Associating
  6384. handlers with small blocks of code helps to narrow the possibilities, making
  6385. it easier to program recovery actions. The placement of handlers in small
  6386. blocks within a subprogram or task body also allows resumption of the
  6387. subprogram or task after the recovery actions. If you do not handle exceptions
  6388. within blocks, the only action available to the handlers is to shut down the
  6389. task or subprogram as prescribed in Guideline .
  6390.  
  6391. note
  6392.  
  6393. The optimal size for the sections of code you choose to protect by a block and 
  6394. its exception handlers is very application-dependent. Too small a granularity
  6395. forces you to expend much more effort in programming for abnormal actions than 
  6396. for the normal algorithm. Too large a granularity reintroduces the problems of 
  6397. determining what went wrong and of resuming normal flow.
  6398.  
  6399. 5.9     ERRONEOUS EXECUTION
  6400.  
  6401. An Ada program is erroneous when it violates or extends the rules of the
  6402. language governing program behavior. Neither compilers nor run-time
  6403. environments are able to detect erroneous behavior in all circumstances and
  6404. contexts. As stated in Section 1.6 of Department of Defense (1983), "The
  6405. effects of erroneous execution are unpredictable."  If the compiler does
  6406. detect an instance of an erroneous program, its options are to indicate a
  6407. compile time error, to insert the code to raise Program_Error, possibly to
  6408. write a message to that effect, or to do nothing at all.
  6409.  
  6410. Erroneousness is not a concept unique to Ada. The guidelines below describe or 
  6411. explain the specific instances of erroneousness defined in the Ada Language 
  6412. Reference Manual.  Although Incorrect Order Dependencies is not, strictly 
  6413. speaking, a case of erroneous execution, the rationale for avoiding such 
  6414. dependencies is the same.  Consequently, the guideline is included in this 
  6415. section.
  6416.  
  6417. 5.9.1   Unchecked Conversion
  6418.  
  6419. guideline
  6420.  
  6421. o       Use Unchecked_Conversion only with the utmost care (Department of 
  6422. Defense 1983, w13.10.2). 
  6423.  
  6424. o       Ensure the value resulting from Unchecked_Conversion is in range.
  6425.  
  6426. o       Isolate the use of Unchecked_Conversion in package bodies.
  6427.  
  6428. example
  6429.  
  6430. The following example may run without exception, depending on the 
  6431. implementation:
  6432.  
  6433. ------------------------------------------------------------------------
  6434. with Unchecked_Conversion;
  6435. with Text_IO;
  6436.  
  6437. procedure Test is
  6438.  
  6439.    type Color is (Red, Yellow, Blue);
  6440.  
  6441.    function Integer_To_Color is
  6442.       new Unchecked_Conversion (Source => Integer,
  6443.                 Target => Color);
  6444.  
  6445.    A_Color : Color;
  6446.    List    : array (Color) of Boolean;
  6447.  
  6448.    Data : Boolean;
  6449.  
  6450. begin  -- Test
  6451.  
  6452.    A_Color := Integer_To_Color(15);
  6453.    Data    := List(A_Color);
  6454.    Text_IO.Put_Line(Color'Image(A_Color));
  6455.  
  6456. end Test;
  6457. ------------------------------------------------------------------------
  6458.  
  6459. rationale
  6460.  
  6461. An unchecked conversion is a bit-for-bit copy without regard to the meanings
  6462. attached to those bits and bit positions by either the source or the 
  6463. destination type. The source bit pattern can easily be meaningless in the 
  6464. context of the destination type. Unchecked conversions can create values that 
  6465. violate type constraints on subsequent operations. Unchecked conversion of 
  6466. objects mismatched in size has implementation-dependent results.
  6467.  
  6468. 5.9.2   Unchecked Deallocation
  6469.  
  6470. guideline
  6471.  
  6472. o       Isolate the use of Unchecked_Deallocation in package bodies.
  6473.  
  6474. rationale
  6475.  
  6476. Most of the reasons for using Unchecked_Deallocation with caution have been
  6477. given in Guideline . When this feature is used, there is no checking that
  6478. there is only one access path to the storage being deallocated. Thus, any
  6479. other access paths are not made null. Depending on such a check is erroneous.
  6480.  
  6481. 5.9.3   Dependence on Parameter Passing Mechanism
  6482.  
  6483. guideline
  6484.  
  6485. o       Do not write code whose correct execution depends on the particular 
  6486. parameter passing mechanism used by an implementation (Department of Defense 
  6487. 1983 and Cohen 1986).
  6488.  
  6489. example
  6490.  
  6491. The output of this program depends on the particular parameter passing 
  6492. mechanism that was used:
  6493.  
  6494. ------------------------------------------------------------------------
  6495. with Text_IO;
  6496.  
  6497. procedure Outer is
  6498.  
  6499.    type Coordinates is
  6500.       record
  6501.      X : Integer := 0;
  6502.      Y : Integer := 0;
  6503.       end record;
  6504.  
  6505.    Outer_Point : Coordinates;
  6506.  
  6507.    package Integer_IO is
  6508.       new Text_IO.Integer_IO (Num => Integer);
  6509.  
  6510.    ---------------------------------------------------------------------
  6511.    procedure Inner (Inner_Point : in out Coordinates) is
  6512.    begin
  6513.       Inner_Point.X := 5;
  6514.  
  6515.       -- The following line causes the output of the program to
  6516.       -- depend on the parameter passing mechanism.
  6517.       Integer_IO.Put(Outer_Point.X);
  6518.    end Inner;
  6519.    ---------------------------------------------------------------------
  6520.  
  6521. begin  -- Outer
  6522.    Integer_IO.Put(Outer_Point.X);
  6523.    Inner         (Outer_Point);
  6524.    Integer_IO.Put(Outer_Point.X);
  6525. end Outer;
  6526. ------------------------------------------------------------------------
  6527.  
  6528. If the parameter passing mechanism is by copy, the results on the standard 
  6529. output file are:
  6530.  
  6531. 0 0 5
  6532.  
  6533. If the parameter passing mechanism is by reference, the results are:
  6534.  
  6535. 0 5 5
  6536.  
  6537. rationale
  6538.  
  6539. The language definition specifies that a parameter whose type is an array, 
  6540. record, or task type can be passed by copy or reference. It is erroneous to 
  6541. assume that either mechanism is used in a particular case.
  6542.  
  6543. exceptions
  6544.  
  6545. Frequently, when interfacing Ada to foreign code, dependence on parameter 
  6546. passing mechanisms used by a particular implementation is unavoidable. In this 
  6547. case, isolate the calls to the foreign code in an interface package that 
  6548. exports operations that do not depend on the parameter-passing mechanism.
  6549.  
  6550. 5.9.4   Multiple Address Clauses
  6551.  
  6552. guideline
  6553.  
  6554. o    Use address clauses to map variables and entries to the hardware
  6555. device or memory, not to model the FORTRAN "equivalence" feature.
  6556.  
  6557. example
  6558.  
  6559. Single_Address : constant ...
  6560.  
  6561. Interrupt_Vector_Table : Hardware_Array;
  6562. for Interrupt_Vector_Table use at Single_Address;
  6563.  
  6564. rationale
  6565.  
  6566. The result of specifying a single address for multiple objects or program
  6567. units is undefined, as is specifying multiple addresses for a single object or
  6568. program unit. Specifying multiple address clauses for an interrupt entry is
  6569. also undefined. It does not necessarily overlay objects or program units, or
  6570. associate a single entry with more than one interrupt.
  6571.  
  6572. 5.9.5   Suppression of Exception Check
  6573.  
  6574. guideline
  6575.  
  6576. o       Do not suppress exception checks during development.
  6577.  
  6578. o       Minimize suppression of exception checks during operation.
  6579.  
  6580. S       If necessary, introduce blocks that encompass the smallest range of 
  6581. statements that can safely have exception checking removed.
  6582.  
  6583. rationale
  6584.  
  6585. If you disable exception checks and program execution results in a condition
  6586. in which an exception would otherwise occur, the program execution is
  6587. erroneous.  The results are unpredictable. Further, you must still be prepared
  6588. to deal with the suppressed exceptions if they are raised in and propagated
  6589. from the bodies of subprograms, tasks, and packages you call.
  6590.  
  6591. By minimizing the code which has exception checking removed, you increase the
  6592. reliability of the program.  There is a rule of thumb which suggests that 20
  6593. percent of the code is responsible for 80 percent of the CPU time.  So once
  6594. you have identified the code that actually needs exception checking removed,
  6595. it is wise to isolate it in a block (with appropriate comments) and leave the
  6596. surrounding code with exception checking in effect.
  6597.  
  6598. 5.9.6   Initialization
  6599.  
  6600. guideline
  6601.  
  6602. o       Initialize all objects prior to use.
  6603.  
  6604. o       Ensure elaboration of an entity before using it.
  6605.  
  6606. o       Use function calls in declarations cautiously.
  6607.  
  6608. example
  6609.  
  6610. ------------------------------------------------------------------------
  6611. package Robot_Controller is
  6612.  
  6613.    ...
  6614.    function Sense return Position;
  6615.    ...
  6616.  
  6617. end Robot_Controller;
  6618.  
  6619. ------------------------------------------------------------------------
  6620. package body Robot_Controller is
  6621.  
  6622.    ...
  6623.    Goal : Position := Sense;       -- This raises Program_Error
  6624.    ...
  6625.  
  6626.    ---------------------------------------------------------------------
  6627.    function Sense return Position is
  6628.    begin
  6629.       ...
  6630.    end Sense;
  6631.    ---------------------------------------------------------------------
  6632.  
  6633. begin  -- Robot_Controller
  6634.    Goal := Sense;                  -- The function has been elaborated.
  6635.  
  6636.    ...
  6637. end Robot_Controller;
  6638. ------------------------------------------------------------------------
  6639.  
  6640. rationale
  6641.  
  6642. Ada does not define an initial default value for objects of any type other
  6643. than access types. Using the value of an object before it has been assigned a
  6644. value causes unpredictable behavior, possibly raising an exception. Objects
  6645. can be initialized implicitly by declaration or explicitly by assignment
  6646. statements.  Initialization at the point of declaration is safest as well as
  6647. easiest for maintainers. You can also specify default values for components of
  6648. records as part of the type declarations for those records.
  6649.  
  6650. Ensuring initialization does not imply initialization at the declaration. In 
  6651. the example above, Goal must be initialized via a function call. This cannot 
  6652. occur at the declaration, because the function Sense has not yet been 
  6653. elaborated, but can occur later as part of the sequence of statements of the 
  6654. body of the enclosing package.
  6655.  
  6656. An unelaborated function called within a declaration (initialization) raises
  6657. the exception, Program_Error, that must be handled outside of the unit
  6658. containing the declarations. This is true for any exception the function
  6659. raises even if it has been elaborated.
  6660.  
  6661. If an exception is raised by a function call in a declaration, it is not 
  6662. handled in that immediate scope. It is raised to the enclosing scope. This can 
  6663. be controlled by nesting blocks.
  6664.  
  6665. note
  6666.  
  6667. Sometimes, elaboration order can be dictated with pragma Elaborate. Pragma 
  6668. Elaborate only applies to library units. 
  6669.  
  6670. 5.9.7   Direct_IO and Sequential_IO
  6671.  
  6672. guideline
  6673.  
  6674. o       Ensure that values obtained from Direct_IO and Sequential_IO are in 
  6675. range.
  6676.  
  6677. rationale
  6678.  
  6679. As with Unchecked_Conversion, there is no check on the value obtained from the 
  6680. read operations found in Direct_IO and Sequential_IO.  See Guideline 5.9.1 for 
  6681. an example.
  6682.  
  6683. note
  6684.  
  6685. It is sometimes difficult to force an optimizing compiler to perform the 
  6686. necessary checks on a value that the compiler believes is in range.  Most 
  6687. compiler vendors allow the option of suppressing optimization which can be 
  6688. helpful.
  6689.  
  6690. 5.9.8   Incorrect Order Dependencies
  6691.  
  6692. guideline
  6693.  
  6694. o       Avoid depending on the order in which certain constructs in Ada are 
  6695. evaluated (see Department of Defense 1983, I-17).
  6696.  
  6697. rationale
  6698.  
  6699. As stated in the Ada Language Reference Manual, an incorrect order dependency 
  6700. may arise whenever ". . . different parts of a given construct are to be
  6701. executed in some order that is not defined by the language. . . .  The 
  6702. construct is incorrect if execution of these parts in a different order would 
  6703. have a different effect."  (Department of Defense 1983, w1.6).
  6704.  
  6705. While an incorrect order dependency may not adversely affect the program on a
  6706. certain implementation, the code might not execute correctly when it is
  6707. ported.  Avoid incorrect order dependencies, but also recognize that even an
  6708. unintentional error of this kind could prohibit portability.
  6709.  
  6710. 5.10    SUMMARY
  6711.  
  6712. optional parts of the syntax
  6713.  
  6714. o       Associate names with loops when they are nested.
  6715.  
  6716. o       Associate names with blocks when they are nested.
  6717.  
  6718. o       Use loop names on all exit statements from nested loops.
  6719.  
  6720. o       Include the simple name at the end of a package specification and body.
  6721.  
  6722. o       Include the simple name at the end of a task specification and body.
  6723.  
  6724. o       Include the simple name at the end of an accept statement.
  6725.  
  6726. o       Include the designator at the end of a subprogram body. 
  6727.  
  6728. parameter lists
  6729.  
  6730. o       Name formal parameters descriptively to reduce the need for comments.
  6731.  
  6732. o       Use named parameter association in calls of infrequently used 
  6733. subprograms or entries with many formal parameters.
  6734.  
  6735. o       Use named association when instantiating generics.
  6736.  
  6737. o       Use named association for clarification when the actual parameter is 
  6738. any literal or expression.
  6739.  
  6740. o       Use named association when supplying a nondefault value to an optional 
  6741. parameter.
  6742.  
  6743. o       Provide default parameters to allow for occasional, special use of 
  6744. widely used subprograms or entries.
  6745.  
  6746. o       Place default parameters at the end of the formal parameter list.
  6747.  
  6748. o       Consider providing default values to new parameters added to an 
  6749. existing subprogram.
  6750.  
  6751. o       Show the mode indication of all procedure and entry parameters.
  6752.  
  6753. o       Use in out only when the parameter is both read from and updated.
  6754.  
  6755. types
  6756.  
  6757. o       Use existing types as building blocks by deriving new types from them.
  6758.  
  6759. o       Use range constraints on subtypes.
  6760.  
  6761. o       Define new types, especially derived types, to include the largest set 
  6762. of possible values, including boundary values.
  6763.  
  6764. o    Constrain the ranges of derived types with subtypes, excluding
  6765. boundary values.
  6766.  
  6767. o       Avoid anonymous types.
  6768.  
  6769. o       Use anonymous types for array variables when no suitable type exists 
  6770. and the array will not be referenced as a whole.
  6771.  
  6772. o       Use limited private types in preference to private types. 
  6773.  
  6774. o       Use private types in preference to nonprivate types.
  6775.  
  6776. o       Explicitly export needed operations rather than easing restrictions.
  6777.  
  6778. data structures
  6779.  
  6780. o       Use records to group heterogeneous but related data.
  6781.  
  6782. o       Consider records to map to I/O device data.
  6783.  
  6784. o       Record structures should not always be flat. Factor out common parts.
  6785.  
  6786. o       For a large record structure, group related components into smaller 
  6787. subrecords.
  6788.  
  6789. o       For nested records, pick element names that read well when inner 
  6790. elements are referenced.
  6791.  
  6792. o       Differentiate between static and dynamic data. Use dynamically 
  6793. allocated objects with caution.
  6794.  
  6795. o       Use dynamically allocated data structures only when it is necessary to 
  6796. create and destroy them dynamically or to be able to reference them by 
  6797. different names.
  6798.  
  6799. o       Do not drop pointers to undeallocated objects.
  6800.  
  6801. o       Do not leave dangling references to deallocated objects.
  6802.  
  6803. o       Initialize all access variables and components within a record.
  6804.  
  6805. o       Do not rely on memory deallocation.
  6806.  
  6807. o       Deallocate explicitly.
  6808.  
  6809. o       Use length clauses to specify total allocation size.
  6810.  
  6811. o       Provide handlers for Storage_Error.
  6812.  
  6813. expressions
  6814.  
  6815. o       Use 'First or 'Last instead of numeric literals to represent the first 
  6816. or last values of a range.
  6817.  
  6818. o       Use the type or subtype name of the range instead of 'First .. 'Last.
  6819.  
  6820. o       Use array attributes 'First, 'Last, or 'Length instead of numeric 
  6821. literals for accessing arrays.
  6822.  
  6823. o    Use the 'Range of the array instead of the name of the index subtype
  6824. to express a range.
  6825.  
  6826. o       Use 'Range instead of 'first .. 'Last to express a range.
  6827.  
  6828. o       Use parentheses to specify the order of subexpression evaluation to 
  6829. clarify expressions.
  6830.  
  6831. o       Use parentheses to specify the order of evaluation for subexpressions 
  6832. whose correctness depends on left to right evaluation.
  6833.  
  6834. o       Avoid names and constructs that rely on the use of negatives.
  6835.  
  6836. o       Choose names of flags so they represent states that can be used in 
  6837. positive form.
  6838.  
  6839. o       Use short-circuit forms of the logical operators.
  6840.  
  6841. o       Use <= and >= in relational expressions with real operands instead of 
  6842. =.
  6843.  
  6844. statements
  6845.  
  6846. o       Minimize the depth of nested expressions.
  6847.  
  6848. o       Minimize the depth of nested control structures.
  6849.  
  6850. o       Try simplification heuristics.
  6851.  
  6852. o       Use slices rather than a loop to copy part of an array.
  6853.  
  6854. o       Never use an others choice in a case statement.
  6855.  
  6856. o       Do not use ranges of enumeration literals in case statements.
  6857.  
  6858. o       Use for loops whenever possible.
  6859.  
  6860. o    Use while loops when the number of iterations cannot be calculated
  6861. before entering the loop, but a simple continuation condition can be applied
  6862. at the top of the loop.
  6863.  
  6864. o       Use plain loops with exit statements for more complex situations.
  6865.  
  6866. o       Avoid exit statements in while and for loops.
  6867.  
  6868. o       Minimize the number of ways to exit a loop.
  6869.  
  6870. o       Use exit statements to enhance the readability of loop termination 
  6871. code.
  6872.  
  6873. o       Use exit when ... rather than if ... then exit whenever possible.
  6874.  
  6875. o       Review exit statement placement.
  6876.  
  6877. o       Consider specifying bounds on loops.
  6878.  
  6879. o       Consider specifying bounds on recursion.
  6880.  
  6881. o       Do not use goto statements.
  6882.  
  6883. o       Minimize the number of returns from a subprogram.
  6884.  
  6885. o       Highlight returns with comments or white space to keep them from being 
  6886. lost in other code. 
  6887.  
  6888. o       Use blocks to localize the scope of declarations.
  6889.  
  6890. o       Use blocks to perform local renaming.
  6891.  
  6892. o       Use blocks to define local exception handlers.
  6893.  
  6894. o       Use an aggregate instead of a sequence of assignments to assign values 
  6895. to all components of a record.
  6896.  
  6897. o    Use an aggregate instead of a temporary variable when building a
  6898. record to pass as an actual parameter.
  6899.  
  6900. o       Use positional association only when there is a conventional ordering 
  6901. of the arguments.
  6902.  
  6903. visibility
  6904.  
  6905. o       Minimize using the use clause.
  6906.  
  6907. o       Consider using the use clause in the following situations:
  6908.  
  6909. -       Infix operators are needed
  6910.  
  6911. -       Standard packages are needed and no ambiguous references are introduced
  6912.  
  6913. -       References to enumeration literals are needed
  6914.  
  6915. o       Consider the renames clause to avoid the use clause.
  6916.  
  6917. o       Localize the effect of all use clauses.
  6918.  
  6919. o       Rename a long, fully qualified name to reduce the complexity if it 
  6920. becomes unwieldy (Guideline ).
  6921.  
  6922. o       Rename declarations for visibility purposes rather than using the use 
  6923. clause, especially for infix operators (Guideline ).
  6924.  
  6925. o    Rename parts when interfacing to reusable components originally
  6926. written with nondescriptive or inapplicable nomenclature.
  6927.  
  6928. o       Use a project-wide standard list of abbreviations to rename common
  6929. packages.
  6930.  
  6931. o       Limit overloading to widely used subprograms that perform similar 
  6932. actions on arguments of different types.
  6933.  
  6934. o       Preserve the conventional meaning of overloaded operators.
  6935.  
  6936. o       Use "+" to identify adding, joining, increasing, and enhancing kinds of
  6937. functions. 
  6938.  
  6939. o       Use "-" to identify subtraction, separation, decreasing, and depleting
  6940. kinds of functions.
  6941.  
  6942. o       Do not depend on the definition of equality provided by private types.
  6943.  
  6944. o       When overloading the equality operator for limited private types, 
  6945. maintain the properties of an algebraic equivalence relation.
  6946.  
  6947. using exceptions
  6948.  
  6949. o       Avoid causing exceptions to be raised when it is easy and efficient to 
  6950. do so.
  6951.  
  6952. o       Provide handlers for exceptions which cannot be avoided.
  6953.  
  6954. o       Use exception handlers to enhance readability by separating fault 
  6955. handling from normal execution.
  6956.  
  6957. o       Do not use exceptions and exception handlers as goto statements.
  6958.  
  6959. o       Use caution when programming handlers for others.
  6960.  
  6961. o       Provide a handler for others in suitable frames to protect against 
  6962. unexpected exceptions being propagated without bound, especially in safety 
  6963. critical systems.
  6964.  
  6965. o       Use others only to catch exceptions you cannot enumerate explicitly, 
  6966. preferably only to flag a potential abort.
  6967.  
  6968. o       Avoid using others during development.
  6969.  
  6970. o       Handle all exceptions, both user and predefined.
  6971.  
  6972. o    For every exception that might be raised, provide a handler in
  6973. suitable frames to protect against undesired propagation outside the
  6974. abstraction.
  6975.  
  6976. o       Do not rely on being able to identify the fault raising predefined or 
  6977. implementation-defined exceptions.
  6978.  
  6979. o       Use blocks to associate localized sections of code with their own 
  6980. exception handlers.
  6981.  
  6982. erroneous execution
  6983.  
  6984. o       Use Unchecked_Conversion only with the utmost care. 
  6985.  
  6986. o       Ensure the value resulting from Unchecked_Conversion is in range.
  6987.  
  6988. o       Isolate the use of UncheckeD_Conversion in package bodies.
  6989.  
  6990. o       Isolate the use of Unchecked_Deallocation in package bodies.
  6991.  
  6992. o       Do not write code whose correct execution depends on the particular 
  6993. parameter passing mechanism used by an implementation.
  6994.  
  6995. o    Use address clauses to map variables and entries to the hardware
  6996. device or memory, not to model the FORTRAN "equivalence" feature.
  6997.  
  6998. o       Do not suppress exception checks during development.
  6999.  
  7000. o       Minimize suppression of exception checks during operation.
  7001.  
  7002. o       If necessary, introduce blocks that encompass the smallest range of 
  7003. statements that can safely have exception checking removed.
  7004.  
  7005. o       Initialize all objects prior to use.
  7006.  
  7007. o       Ensure elaboration of an entity before using it.
  7008.  
  7009. o       Use function calls in declarations cautiously.
  7010.  
  7011. o       Ensure that values obtained from Direct_IO and Sequential_IO are in 
  7012. range.
  7013.  
  7014. o       Avoid depending on the order in which certain constructs in Ada are 
  7015. evaluated.
  7016.  
  7017.  
  7018.  
  7019.  
  7020. CHAPTER 6
  7021. Concurrency
  7022.  
  7023. Concurrency exists as either apparent concurrency or real concurrency. In a 
  7024. single processor environment apparent concurrency is the result of interleaved 
  7025. execution of concurrent activities. In a multi-processor environment real
  7026. concurrency is the result of overlapped execution of concurrent activities.
  7027.  
  7028. Concurrent programming is more difficult and error prone than sequential
  7029. programming. The concurrent programming features of Ada are designed to make
  7030. it easier to write and maintain concurrent programs which behave consistently
  7031. and predictably, and avoid such problems as deadlock and starvation. The
  7032. language features themselves cannot guarantee that programs have these
  7033. desirable properties. They must be used with discipline and care, a process
  7034. supported by the guidelines in this chapter.
  7035.  
  7036. The correct usage of Ada concurrency features results in reliable, reusable, 
  7037. and portable software. For example, using tasks to model concurrent activities 
  7038. and using the rendezvous for the required synchronization between cooperating 
  7039. concurrent tasks. Misuse of language features results in software that is 
  7040. unverifiable and difficult to reuse or port.  For example, using task 
  7041. priorities or delays to manage synchronization is not portable.  It is also 
  7042. important that a reusable component not make assumptions about the order or 
  7043. speed of task execution (i.e., about the compilers tasking implementation).
  7044.  
  7045. Avoid assuming that the rules of good sequential program design can be
  7046. applied, by analogy, to concurrent programs. For example, while multiple
  7047. returns from subprograms should be discouraged (Guideline ), multiple task
  7048. exits or termination points are often necessary and desirable.
  7049.  
  7050. 6.1     TASKING
  7051.  
  7052. Many problems map naturally to a concurrent programming solution. By
  7053. understanding and correctly using the Ada language tasking features, you can
  7054. produce solutions that are independent of target implementation. Tasks provide
  7055. a means, within the Ada language, of expressing concurrent asynchronous
  7056. threads of control and relieving programmers from the problem of explicitly
  7057. controlling multiple concurrent activities.
  7058.  
  7059. Tasks cooperate to perform the required activities of the software. 
  7060. Synchronization is required between individual tasks. The Ada rendezvous 
  7061. provides a powerful mechanism for this synchronization.
  7062.  
  7063. 6.1.1   Tasks
  7064.  
  7065. guideline
  7066.  
  7067. o       Use tasks to model asynchronous entities within the problem domain.
  7068.  
  7069. o       Use tasks to control or synchronize access to tasks or devices.
  7070.  
  7071. o       Use tasks to define concurrent algorithms.
  7072.  
  7073. example
  7074.  
  7075. Asynchronous entities are the naturally concurrent objects within the problem 
  7076. domain. These tend to be objects in the problem space that have state, such as 
  7077. elevators in an elevator control system or satellites in a global positioning 
  7078. system. The following is an example for an elevator control system:
  7079.  
  7080. ------------------------------------------------------------------------
  7081. package Elevator_Objects is
  7082.  
  7083.    ...
  7084.    type Elevator_States is (Moving, Idle, Stopped, At_Floor);
  7085.    type Up_Down         is (Up, Down);
  7086.  
  7087.    ---------------------------------------------------------------------
  7088.    task type Elevators is
  7089.  
  7090.       entry Initialize;
  7091.       entry Close_Door;
  7092.       entry Open_Door;
  7093.       entry Stop;
  7094.       entry Idle;
  7095.       entry Start         (Direction        : in     Up_Down);
  7096.       entry Current_State (My_State         :    out Elevator_States;
  7097.                Current_Location :    out Float);
  7098.  
  7099.    end Elevators;
  7100.    ---------------------------------------------------------------------
  7101.  
  7102.    ...
  7103.  
  7104. end Elevator_Objects;
  7105. ------------------------------------------------------------------------
  7106.  
  7107. A task that manages updates from multiple concurrent user tasks to a graphic 
  7108. display is an example of a control and synchronization task. 
  7109.  
  7110. Multiple tasks that implement the decomposition of a large matrix 
  7111. multiplication algorithm is an example of an opportunity for real concurrency 
  7112. in a multi-processor target environment. In a single processor target
  7113. environment this approach may not be justified. 
  7114.  
  7115. A task that updates a radar display every 30 milliseconds is an example of a 
  7116. cyclic activity supported by a task. 
  7117.  
  7118. A task that detects an over-temperature condition in a nuclear reactor and
  7119. performs an emergency shutdown of the systems is an example of a task to 
  7120. support a high priority activity.
  7121.  
  7122. rationale
  7123.  
  7124. These guidelines reflect the intended uses of tasks. They all revolve around
  7125. the fact that a task has its own thread of control separate from the main
  7126. subprogram. The conceptual model for a task is a separate program with its own
  7127. virtual processor. This provides the opportunity to model entities from the
  7128. problem domain in terms more closely resembling those entities, and the
  7129. opportunity to handle physical devices as a separate concern from the main
  7130. algorithm of the application. Tasks also allow naturally concurrent activities
  7131. which can be mapped to multiple processors when available.
  7132.  
  7133. Resources shared between multiple tasks, such as devices and abstract data
  7134. structures, require control and synchronization since their operations are
  7135. not atomic. Drawing a circle on a display may require that many low level
  7136. operations be performed without interruption by another task. A display
  7137. manager would ensure that no other task accesses the display until all these
  7138. operations are complete.
  7139.  
  7140. 6.1.2   Anonymous Task Types
  7141.  
  7142. guideline
  7143.  
  7144. o       Use anonymous task types for single instances.
  7145.  
  7146. example
  7147.  
  7148. The example below illustrates the syntactic differences between the kinds of
  7149. tasks discussed here. Buffer is static and has a name, but its type is
  7150. anonymous. Because it is declared explicitly, the task type Buffer_Manager is
  7151. not anonymous. Channel is static and has a name, and its type is not
  7152. anonymous.  Like all dynamic objects, Encrypted_Packet_Queue.all is
  7153. essentially anonymous, but its type is not.
  7154.  
  7155. task      Buffer;
  7156. task type Buffer_Manager;
  7157. type Replaceable_Buffer is access Buffer_Manager;
  7158.  
  7159. ...
  7160. Encrypted_Packet_Queue : Replaceable_Buffer;
  7161. Channel                : Buffer_Manager;
  7162.  
  7163. ...
  7164. Encrypted_Packet_Queue := new Buffer_Manager;
  7165. ...
  7166.  
  7167. rationale
  7168.  
  7169. The use of named tasks of anonymous type avoids a proliferation of task types 
  7170. that are only used once, and the practice communicates to maintainers that 
  7171. there are no other task objects of that type. If the need arises later to have 
  7172. additional tasks of the same type, then the work required to convert a named 
  7173. task to a task type is minimal.
  7174.  
  7175. The consistent and logical use of task types, when necessary, contributes to 
  7176. understandability. Identical tasks can be derived from a common task type. 
  7177. Dynamically allocated task structures are necessary when you must create and 
  7178. destroy tasks dynamically or when you must reference them by different names.
  7179.  
  7180. note
  7181.  
  7182. Though changing the task from an anonymous type to a task type is trivial,
  7183. structural changes to the software architecture may not be trivial.
  7184. Introduction of multiple tasks of the task type may require the scope of the
  7185. task type to change and may change the behavior of the network of
  7186. synchronizing tasks.
  7187.  
  7188. 6.1.3   Dynamic Tasks
  7189.  
  7190. guideline
  7191.  
  7192. o       Justify the use of dynamically allocated task objects.
  7193.  
  7194. o       Avoid disassociating a dynamic task from all names.
  7195.  
  7196. example
  7197.  
  7198. The approach used in the following example below is not recommended. The 
  7199. example shows why caution is required with dynamically allocated task objects. 
  7200. It illustrates how a dynamic task can be disassociated from its name.
  7201.  
  7202. task type Radar_Track;
  7203. type      Radar_Track_Pointer is access Radar_Track;
  7204.  
  7205. Current_Track : Radar_Track_Pointer;
  7206.  
  7207. ---------------------------------------------------------------------
  7208. task body Radar_Track is
  7209. begin
  7210.    loop
  7211.       -- update tracking information
  7212.       ...
  7213.       -- exit when out of range
  7214.       delay 1.0;
  7215.    end loop;
  7216.  
  7217. ...
  7218. end Radar_Track;
  7219. ---------------------------------------------------------------------
  7220.  
  7221. ...
  7222. loop
  7223.    ...
  7224.  
  7225.    -- Unless some code deals with non-null values of Current_Track,
  7226.    -- (such as an array of existing tasks)
  7227.    -- this assignment leaves the existing Radar_Track task running with
  7228.    -- no way to signal it to abort or to instruct the system to
  7229.    -- reclaim its resources.
  7230.    Current_Track := new Radar_Track;
  7231.  
  7232.    ...
  7233. end loop;
  7234.  
  7235. rationale
  7236.  
  7237. A dynamically allocated task object is a task object created by the execution
  7238. of an allocator.  Allocators can be used to avoid limiting the number of
  7239. tasks.  Memory and timing requirements are positively or negatively affected
  7240. by the decision to use dynamic tasks.  Both creation and deletion of dynamic
  7241. tasks and scheduling of dormant static tasks adversely affect performance.
  7242. Dormant static tasks incur memory overhead that can be avoided using dynamic
  7243. tasks.  Creation and deletion of dynamic tasks is typically more expensive
  7244. than scheduling overhead in terms of CPU time.
  7245.  
  7246. Allocated task objects referenced by access variables allow you to generate 
  7247. aliases; multiple references to the same object.  Anomalous behavior can arise 
  7248. when you reference an aborted task by another name.
  7249.  
  7250. A dynamically allocated task that is not associated with a name (a "dropped
  7251. pointer") cannot be referenced for the purpose of making entry calls, nor can 
  7252. it be the direct target of an abort statement (see Guideline ).
  7253.  
  7254. 6.1.4   Priorities
  7255.  
  7256. guideline
  7257.  
  7258. o       Do not rely on pragma Priority to prioritize the service of entries.
  7259.  
  7260. o       Arrange task bodies in order of their priorities (if possible).
  7261.  
  7262. example
  7263.  
  7264. For example, let the tasks have the following priorities:
  7265.  
  7266. task T1 ... pragma Priority (High)   ... Server.Operation ...
  7267. task T2 ... pragma Priority (Medium) ... Server.Operation ...
  7268. task Server                          ... accept Operation ...
  7269.  
  7270. At some point in its execution, T1 is blocked. Otherwise, T2 and Server may
  7271. never execute. If T1 is blocked, it is possible for T2 to reach its call to
  7272. Server's entry (Operation) before T1. Suppose this has happened and that T1
  7273. now makes its entry call before Server has a chance to accept T2's call.
  7274.  
  7275. This is the timeline of events so far:
  7276.  
  7277. T1 blocks
  7278. T2 calls Server.Operation
  7279. T1 unblocks
  7280. T1 calls Server.Operation
  7281.  
  7282. Does Server accept the call from T1 or from T2?
  7283.  
  7284. Some people might expect that, due to its higher priority, T1's call would be
  7285. accepted by Server before that of T2. However, entry calls are queued in
  7286. first-in-first-out (FIFO) order and not queued in order of priority.
  7287. Therefore, the synchronization between T1 and Server is not affected by T1's
  7288. priority.  As a result, the call from T2 is accepted first.  This is a form of
  7289. priority inversion.
  7290.  
  7291. A solution might be to provide an entry for a High priority user and an entry 
  7292. for a Medium priority user. 
  7293.  
  7294. ---------------------------------------------------------------------
  7295. task Server is
  7296.    entry Operation_High_Priority;
  7297.    entry Operation_Medium_Priority;
  7298.    ...
  7299. end Server;
  7300.  
  7301. ---------------------------------------------------------------------
  7302. task body Server is
  7303. begin
  7304.  
  7305.    loop
  7306.       select
  7307.      accept Operation_High_Priority do
  7308.         Operation;
  7309.      end Operation_High_Priority;
  7310.       else  -- accept any priority
  7311.  
  7312.      select
  7313.         accept Operation_High_Priority do
  7314.            Operation;
  7315.         end Operation_High_Priority;
  7316.      or
  7317.         accept Operation_Medium_Priority do
  7318.            Operation;
  7319.         end Operation_Medium_Priority;
  7320.      or
  7321.         terminate;
  7322.      end select;
  7323.       end select;
  7324.  
  7325.    end loop;
  7326.  
  7327. ...
  7328. end Server;
  7329. ---------------------------------------------------------------------
  7330.  
  7331. However, in this approach T1 still waits for one execution of Operation when
  7332. T2 has already gained control of the task Server. In addition, the approach
  7333. increases the communication complexity (see Guideline ).
  7334.  
  7335. rationale
  7336.  
  7337. The pragma Priority allows relative priorities to be placed on tasks to 
  7338. accomplish scheduling.  Precision becomes a critical issue with hard-deadline 
  7339. scheduling.  However, there are certain problems associated with using 
  7340. priorities that warrant caution.  
  7341.  
  7342. Priority inversion occurs when lower priority tasks are given service while
  7343. higher priority tasks remain blocked.  In the above example, this occurred
  7344. because entry queues are serviced in FIFO order, not by priority.  There is
  7345. another situation referred to as a race condition.  A program like the one in
  7346. the first example might often behave as expected as long as T1 calls
  7347. Server.Operation only when T2 is not already using Server.Operation or
  7348. waiting.  You cannot rely on T1 always winning the race, since that behavior
  7349. would be due more to fate than to the programmed priorities.  Race conditions
  7350. change when either adding code to an unrelated task or porting this code to a
  7351. new target.  Task priorities are not a means of achieving mutual exclusion.
  7352.  
  7353. Arranging task bodies in order of priority will elaborate the higher priority 
  7354. tasks first. 
  7355.  
  7356. exceptions
  7357.  
  7358. When there are dependencies between tasks, the dependencies will influence the
  7359. order in which the tasks should be elaborated. In these cases, the
  7360. dependencies in conjunction with the task priorities should be used to order
  7361. the task bodies.
  7362.  
  7363. note
  7364.  
  7365. Work is being done to minimize these problems, including the introduction of a
  7366. scheduling algorithm known as the priority ceiling protocol (Goodenough and
  7367. Sha 1988). The priority ceiling protocol reduces the blocking time that causes
  7368. priority inversion to only one critical region (defined by the entries in a
  7369. task). The protocol also eliminates deadlock unless a task recursively tries
  7370. to access a critical region. This protocol is based on priority inheritance
  7371. and thus deviates from the standard Ada tasking paradigm.
  7372.  
  7373. Priorities are used to control when tasks run relative to one another.  When 
  7374. both tasks are not blocked waiting at an entry, the highest priority task is 
  7375. given precedence.  However, the most critical tasks in an application do not 
  7376. always have the highest priority.  For example, support tasks or tasks with 
  7377. small periods may have higher priorities, because they need to run frequently.
  7378.  
  7379. 6.1.5   Delay Statements
  7380.  
  7381. guideline
  7382.  
  7383. o    Do not depend on a particular delay being achievable (Nissen and
  7384. Wallis 1984).
  7385.  
  7386. o       Do not use a busy waiting loop instead of a delay.
  7387.  
  7388. o       Design to limit polling to those cases where absolutely necessary.
  7389.  
  7390. o       Do not use knowledge of the execution pattern of tasks to achieve 
  7391. timing requirements.
  7392.  
  7393. example
  7394.  
  7395. The phase of a periodic task is the fraction of a complete cycle elapsed as 
  7396. measured from a specified reference point. In the following example an 
  7397. inaccurate delay causes the phase of the periodic task to drift over time 
  7398. (i.e., the task starts later and later in the cycle):
  7399.  
  7400. Periodic:
  7401.    loop
  7402.       delay Interval;
  7403.       ...
  7404.    end loop Periodic;
  7405.  
  7406. The following example shows how to compensate for the inaccuracy of the delay 
  7407. statement. This approach works well when the periodic requirement can be 
  7408. satisfied with an average period.  Periodic tasks based on an inaccurate delay 
  7409. can drift from their phase. Prevention of this drift can be achieved by 
  7410. calculating the next time-to-occur based on the actual time of the current
  7411. execution. The following example illustrates this tactic:
  7412.  
  7413. No_Drift:
  7414.    declare
  7415.       use Calendar;
  7416.  
  7417.       -- Interval is a global constant of type Duration
  7418.       Next_Time : Calendar.Time := Calendar.Clock + Interval;
  7419.  
  7420.    begin  -- No_Drift
  7421.       Stable_Periodic:
  7422.      loop
  7423.         delay Next_Time - Clock;
  7424.         ...
  7425.  
  7426.         Next_Time := Next_Time + Interval;
  7427.      end loop Stable_Periodic;
  7428.    end No_Drift;
  7429.  
  7430. rationale
  7431.  
  7432. The Ada language definition only guarantees that the delay time is a minimum.
  7433. The meaning of a delay statement is that the task is not scheduled for
  7434. execution before the interval has expired. In other words, a task becomes
  7435. eligible to resume execution as soon as the amount of time has passed.
  7436. However, there is no guarantee of when (or if) it is scheduled after that
  7437. time.
  7438.  
  7439. A busy wait can interfere with processing by other tasks. It can consume the
  7440. very processor resource necessary for completion of the activity for which it
  7441. is waiting. Even a loop with a delay can have the impact of busy waiting if
  7442. the planned wait is significantly longer then the delay interval. If a task
  7443. has nothing to do, it should be blocked at an accept or select statement.
  7444.  
  7445. Using knowledge of the execution pattern of tasks to achieve timing 
  7446. requirements is nonportable. Ada does not specify the underlying scheduling 
  7447. algorithm.
  7448.  
  7449. 6.2     COMMUNICATION
  7450.  
  7451. The need for tasks to communicate gives rise to most of the problems that make
  7452. concurrent programming so difficult. Used properly, Ada's intertask
  7453. communication features can improve the reliability of concurrent programs;
  7454. used thoughtlessly, they can introduce subtle errors that can be difficult to
  7455. detect and correct.
  7456.  
  7457. 6.2.1   Efficient Task Communications
  7458.  
  7459. guideline
  7460.  
  7461. o       Minimize the work performed during a rendezvous.
  7462.  
  7463. o       Minimize the work performed in the selective wait loop of a task.
  7464.  
  7465. example
  7466.  
  7467. In the following example, the statements in the accept body are performed as 
  7468. part of the execution of both the caller task and the task Server which 
  7469. contains Operation and Operation2. The statements after the accept body are 
  7470. executed before Server can accept additional calls to Operation or Operation2. 
  7471.  
  7472.    ...
  7473.    loop
  7474.       select
  7475.      accept Operation do
  7476.  
  7477.         -- These statements are executed during rendezvous.
  7478.         -- Both caller and server are blocked during this time.
  7479.         ...
  7480.      end Operation;
  7481.  
  7482.      ...
  7483.      -- These statements are not executed during rendezvous.
  7484.      -- Their execution delays getting back to the accept and
  7485.      --   may be a candidate for another task.
  7486.  
  7487.       or
  7488.      accept Operation_2 do
  7489.  
  7490.         -- These statements are executed during rendezvous.
  7491.         -- Both caller and server are blocked during this time.
  7492.         ...
  7493.      end Operation_2;
  7494.  
  7495.       end select;
  7496.       -- These statements are also not executed during rendezvous,
  7497.       -- Their execution delays getting back to the accept and may
  7498.       --   be a candidate for another task.
  7499.  
  7500.    end loop;
  7501.  
  7502. rationale
  7503.  
  7504. Only work that needs to be performed during a rendezvous, such as saving or 
  7505. generating parameters, should be allowed in the accept bodies to minimize the 
  7506. time required to rendezvous.
  7507.  
  7508. When work is removed from the accept body and placed later in the selective
  7509. wait loop, the additional work may still suspend the caller task. If the
  7510. caller task calls entry Operation again before the server task completes its
  7511. additional work, the caller is delayed until the server completes the
  7512. additional work. If the potential delay is unacceptable and the additional
  7513. work does not need to be completed before the next service of the caller task,
  7514. the additional work may form the basis of a new task that will not block the
  7515. caller task.
  7516.  
  7517. note
  7518.  
  7519. In some cases, additional functions may be added to a task. For example, a
  7520. task controlling a communication device may be responsible for a periodic
  7521. function to ensure that the device is operating correctly. This type of
  7522. addition should be done with care realizing that the response time of the task
  7523. is impacted (see rationale).
  7524.  
  7525. exceptions
  7526.  
  7527. Task communication overhead must be balanced with the associated blocking.
  7528. Each time a new task is introduced, there is a timing impact caused by
  7529. scheduling and synchronization with the new task. Be careful when introducing
  7530. tasks to reduce blocking. The reduction in blocking time will cause increased
  7531. task scheduling and synchronization overhead and software architecture
  7532. complexity.
  7533.  
  7534. 6.2.2   Defensive Task Communication
  7535.  
  7536. guideline
  7537.  
  7538. o    Provide a handler for exception Program_Error whenever you cannot
  7539. avoid a selective wait statement whose alternates can all be closed (Honeywell
  7540. 1986).
  7541.  
  7542. o       Make systematic use of handlers for Tasking_Error.
  7543.  
  7544. o       Be prepared to handle exceptions during a rendezvous.
  7545.  
  7546. example
  7547.  
  7548. This block allows recovery from exceptions raised while attempting to 
  7549. communicate a command to another task.
  7550.  
  7551. Accelerate:
  7552.    begin
  7553.       Throttle.Increase(Step);
  7554.  
  7555.    exception
  7556.       when Tasking_Error     =>     ...
  7557.       when Constraint_Error |
  7558.        Numeric_Error     =>     ...
  7559.       when Throttle_Too_Wide =>     ...
  7560.  
  7561.       ...
  7562.    end Accelerate;
  7563.  
  7564. In this select statement, if all the guards happen to be closed, the program
  7565. can continue by executing the else part. There is no need for a handler for
  7566. Program_Error. Other exceptions can still be raised while evaluating the
  7567. guards or attempting to communicate.
  7568.  
  7569. ...
  7570. Guarded:
  7571.    begin
  7572.       select
  7573.      when Condition_1 =>
  7574.         accept Entry_1;
  7575.  
  7576.       or
  7577.      when Condition_2 =>
  7578.         accept Entry_2;
  7579.  
  7580.       else  -- all alternatives closed
  7581.      ...
  7582.       end select;
  7583.    exception
  7584.       when Constraint_Error | Numeric_Error =>
  7585.      ...
  7586.    end Guarded;
  7587.  
  7588. In this select statement, if all the guards happen to be closed, exception 
  7589. Program_Error will be raised. Other exceptions can still be raised while 
  7590. evaluating the guards or attempting to communicate. 
  7591.  
  7592. Guarded:
  7593.    begin
  7594.       select
  7595.      when Condition_1 =>
  7596.         accept Entry_1;
  7597.  
  7598.       or
  7599.      when Condition_2 =>
  7600.         delay Fraction_Of_A_Second;
  7601.       end select;
  7602.  
  7603.    exception
  7604.       when Program_Error     =>  ...
  7605.       when Constraint_Error |
  7606.        Numeric_Error     =>  ...
  7607.    end Guarded;;
  7608. ...
  7609.  
  7610. rationale
  7611.  
  7612. The exception Program_Error is raised if a selective wait statement (select 
  7613. statement containing accepts) is reached, all of whose alternatives are closed 
  7614. (i.e., the guards evaluate to False and there are no alternatives without 
  7615. guards), unless there is an else part. When all alternatives are closed, the 
  7616. task can never again progress, so there is by definition an error in its 
  7617. programming. You must be prepared to handle this error should it occur.
  7618.  
  7619. Since an else part cannot have a guard, it can never be closed off as an 
  7620. alternative action, thus its presence prevents Program_Error. However, an else 
  7621. part, a delay alternative, and a terminate alternative are all mutually 
  7622. exclusive, so you will not always be able to provide an else part. In these 
  7623. cases, you must be prepared to handle Program_Error.
  7624.  
  7625. The exception Tasking_Error can be raised in the calling task whenever it
  7626. attempts to communicate. There are many situations permitting this. Few of
  7627. them are preventable by the calling task.
  7628.  
  7629. If an exception is raised during a rendezvous and not handled in the accept 
  7630. statement, it is propagated to both tasks and must be handled in two places. 
  7631. See Guideline .
  7632.  
  7633. note
  7634.  
  7635. There are other ways to prevent Program_Error at a selective wait. These
  7636. involve leaving at least one alternative unguarded, or proving that at least
  7637. one guard will evaluate True under all circumstances. The point here is that
  7638. you, or your successors, will make mistakes in trying to do this, so you
  7639. should prepare to handle the inevitable exception.
  7640.  
  7641. 6.2.3    Attributes 'Count, 'Callable and 'Terminated
  7642.  
  7643. guideline
  7644.  
  7645. o       Do not depend on the values of the task attributes 'Callable or 
  7646. 'Terminated (Nissen and Wallis 1984).
  7647.  
  7648. o       Do not depend on attributes to avoid Tasking_Error on an entry call. 
  7649.  
  7650. o       Do not depend on the value of the entry attribute 'Count.
  7651.  
  7652. example 
  7653.  
  7654. In the following examples Intercept'Callable is a boolean indicating if a call
  7655. can be made to the task Intercept without raising the exception Tasking_Error.
  7656. Launch'Count indicates the number of callers currently waiting at entry
  7657. Launch.  Intercept'Terminated is a boolean indicating if the task Intercept is
  7658. in terminated state.
  7659.  
  7660. This task is badly programmed because it relies upon the values of the 'Count 
  7661. attributes not changing between evaluating and acting upon them. 
  7662.  
  7663. ---------------------------------------------------------------------
  7664. task body Intercept is
  7665. ...
  7666.  
  7667.    select
  7668.       when Launch'Count > 0 and Recall'Count = 0 =>
  7669.      accept Launch;
  7670.      ...
  7671.  
  7672.    or
  7673.       accept Recall;
  7674.       ...
  7675.    end select;
  7676.  
  7677. ...
  7678. end Intercept;
  7679. ---------------------------------------------------------------------
  7680.  
  7681. If the following code is preempted between evaluating the condition and 
  7682. initiating the call, the assumption that the task is still callable may no 
  7683. longer be valid.
  7684.  
  7685. ...
  7686. if Intercept'Callable then
  7687.    Intercept.Recall;
  7688. end if;
  7689. ...
  7690.  
  7691. rationale
  7692.  
  7693. Attributes 'Callable, 'Terminated, and 'Count are all subject to race 
  7694. conditions. Between the time you reference an attribute and the time you take 
  7695. action the value of the attribute may change. Attributes 'Callable and 
  7696. 'Terminated convey reliable information once they become False and True, 
  7697. respectively. If 'Callable is False, you can expect the callable state to 
  7698. remain constant. If 'Terminated is True, you can expect the task to remain 
  7699. terminated. Otherwise, 'Terminated and 'Callable can change between the time 
  7700. your code tests them and the time it responds to the result. 
  7701.  
  7702. The Ada Language Reference Manual (Department of Defense 1983) itself warns
  7703. about the asynchronous increase and decrease of the value of 'Count. A task
  7704. can be removed from an entry queue due to execution of an abort statement as
  7705. well as expiration of a timed entry call. The use of this attribute in guards
  7706. of a selective wait statement may result in the opening of alternatives which
  7707. should not be opened under a changed value of 'Count.
  7708.  
  7709. 6.2.4   Shared Variables
  7710.  
  7711. guideline
  7712.  
  7713. o       Use the rendezvous mechanism, not shared variables, to pass data 
  7714. between tasks.
  7715.  
  7716. o       Do not use shared variables as a task synchronization device.
  7717.  
  7718. o       Do not reference nonlocal variables in a guard.
  7719.  
  7720. example
  7721.  
  7722. This code will either print the same line more than once, fail to print some 
  7723. lines, or print garbled lines (part of one line followed by part of another) 
  7724. nondeterministically.
  7725.  
  7726. ---------------------------------------------------------------------
  7727. task body Robot_Arm_Driver is
  7728.  
  7729.    Current_Command : Robot_Command;
  7730.  
  7731. begin  -- Robot_Arm_Driver
  7732.    loop
  7733.  
  7734.       Current_Command := Command;
  7735.       -- send to device
  7736.  
  7737.    end loop;
  7738. ...
  7739. end Robot_Arm_Driver;
  7740.  
  7741. ---------------------------------------------------------------------
  7742. task body Stream_Server is
  7743. begin
  7744.    loop
  7745.  
  7746.       Stream_Read(Stream_File, Command);
  7747.  
  7748.    end loop;
  7749. ...
  7750. end Stream_Server;
  7751. ---------------------------------------------------------------------
  7752.  
  7753. This code ensures that a missile cannot be fired unless the doors are open and 
  7754. that the missile cannot be armed unless the doors are shut. In this case the 
  7755. requirement for arming may be derived from the duration that the door may be 
  7756. open (i.e., arm first, open door, launch, close door).
  7757.  
  7758. Doors_Open : Boolean := False;
  7759.  
  7760. ---------------------------------------------------------------------
  7761. task body Intercept is
  7762. begin
  7763.    ...
  7764.  
  7765.    select
  7766.       when Doors_Open = True =>
  7767.      accept Launch;
  7768.      ...
  7769.  
  7770.    or
  7771.       when Doors_Open = False =>
  7772.      accept Arm;
  7773.      ...
  7774.    end select;
  7775.  
  7776. ...
  7777. end Intercept;
  7778. ---------------------------------------------------------------------
  7779.  
  7780. ---------------------------------------------------------------------
  7781. task body Intercept is
  7782.  
  7783.    Local_Doors_Open : Boolean := False;
  7784.  
  7785. begin  -- Intercept
  7786.    ...
  7787.  
  7788.    select
  7789.       when Local_Doors_Open = True =>
  7790.      accept Launch;
  7791.      ...
  7792.  
  7793.    or
  7794.       when Local_Doors_Open = False =>
  7795.      accept Arm;
  7796.      ...
  7797.  
  7798.    or
  7799.       accept Door_Status
  7800.         (Doors_Open : in     Boolean) do
  7801.      Local_Doors_Open := Doors_Open;
  7802.       end Door_Status;
  7803.    end select;
  7804.  
  7805. ...
  7806. end Intercept;
  7807. ---------------------------------------------------------------------
  7808.  
  7809. rationale
  7810.  
  7811. There are many techniques for protecting and synchronizing data access. You 
  7812. must program most of them yourself to use them. It is difficult to write a 
  7813. program that shares data correctly. If it is not done correctly, the 
  7814. reliability of the program suffers. Ada provides the rendezvous to support 
  7815. synchronization and communication of information between tasks. Data that you 
  7816. might be tempted to share can be put into a task body with read and write 
  7817. entries to access it.
  7818.  
  7819. The first example above has a race condition requiring perfect interleaving of
  7820. execution. This code can be made more reliable by introducing a flag that is
  7821. set by Spool_Server and reset by Line_Printer_Driver. An if (condition flag)
  7822. then delay ... else would be added to each task loop in order to ensure that
  7823. the interleaving is satisfied. However, notice that this approach requires a
  7824. delay and the associated rescheduling. Presumably this rescheduling overhead
  7825. is what is being avoided by not using the rendezvous.
  7826.  
  7827. A guard is a conditional select alternative starting with a when (see 9.7.1 in
  7828. Department of Defense 1983). The second example above also has a race
  7829. condition requiring two different things. First, the task that opens the doors
  7830. must open the doors and update Doors_Open before allowing the intercept task
  7831. to continue execution. Second, the run time system evaluation of the guard in
  7832. the select statement cannot occur until the Doors_Open matches the next
  7833. anticipated entry call. If the next call will be to ARM, then you must make
  7834. sure that Doors_Open changes to False before the Intercept task reevaluates
  7835. the select statement. If the select statement is evaluated while Doors_Open is
  7836. True and Doors_Open is subsequently set to False, the select will continue to
  7837. wait on the Launch until a Launch is received. An alternate approach is to use
  7838. Local_Doors_Open in the example. This guarantees that the guards will be
  7839. reevaluated upon a change in the value of Doors_Open.
  7840.  
  7841. exceptions
  7842.  
  7843. For some required synchronizations the rendezvous may not meet time
  7844. constraints. Each case should be analyzed in detail to justify the use of
  7845. pragma Shared, which presumably has less overhead than the rendezvous. Be
  7846. careful to correctly implement a data access synchronization technique.
  7847. Without great effort you might get it wrong. Pragma Shared can serve as an
  7848. expedient against poor run time support systems. Do not always use this as an
  7849. excuse to avoid the rendezvous because implementations are allowed to ignore
  7850. pragma Shared (Nissen and Wallis 1984). When pragma Shared is implemented by
  7851. compilers, the implementation is not always uniform and can still lead to
  7852. nonportable code. Pragma Shared affects only those objects whose storage and
  7853. retrieval are implemented as indivisible operations. Also, pragma Shared can
  7854. only be used for variables of scalar or access type.
  7855.  
  7856. note
  7857.  
  7858. As pointed out above, a guarantee of noninterference may be difficult with 
  7859. implementations that ignore pragma Shared. If you must share data, share the 
  7860. absolute minimum amount necessary, and be especially careful. As always, 
  7861. encapsulate the synchronization portions of code.
  7862.  
  7863. The problem is with variables. Constants, such as tables fixed at compile
  7864. time, may be safely shared between tasks.
  7865.  
  7866. 6.2.5   Tentative Rendezvous Constructs
  7867.  
  7868. guideline
  7869.  
  7870. o       Use caution with conditional entry calls.
  7871.  
  7872. o       Use caution with selective waits with else parts.
  7873.  
  7874. o       Do not depend upon a particular delay in timed entry calls.
  7875.  
  7876. o       Do not depend upon a particular delay in selective waits with delay 
  7877. alternatives.
  7878.  
  7879. example
  7880.  
  7881. The conditional entry call in the following code results in a race condition 
  7882. that may degenerate into a busy waiting loop. The task Current_Position 
  7883. containing entry Request_New_Coordinates may never execute if this task has a 
  7884. higher priority than Current_Position, because this task doesn't release the 
  7885. processing resource.
  7886.  
  7887. ...
  7888. loop
  7889.  
  7890.    select
  7891.       Current_Position.Request_New_Coordinates(X, Y);
  7892.       -- calculate target location based on new coordinates
  7893.       ...
  7894.  
  7895.    else
  7896.       -- calculate target location based on last locations
  7897.       ...
  7898.    end select;
  7899.  
  7900. end loop;
  7901. ...
  7902.  
  7903. The addition of a delay as shown may allow Current_Position to execute until
  7904. it reaches an accept for Request_New_Coordinates.
  7905.  
  7906. ...
  7907. loop
  7908.  
  7909.    select
  7910.       Current_Position.Request_New_Coordinates(X, Y);
  7911.       -- calculate target location based on new coordinates
  7912.       ...
  7913.  
  7914.    else
  7915.       -- calculate target location based on last locations
  7916.       ...
  7917.  
  7918.       delay Next_Execute - Clock;
  7919.       Next_Execute := Next_Execute + Period;
  7920.    end select;
  7921.  
  7922. end loop;
  7923. ...
  7924.  
  7925. The following selective wait with else again does not degenerate into a busy 
  7926. wait loop only because of the addition of a delay statement.
  7927.  
  7928.    loop
  7929.       delay Next_Execute - Clock;
  7930.  
  7931.       select
  7932.      accept Get_New_Message (Message : in     String) do
  7933.         -- copy message to parameters
  7934.         ...
  7935.      end Get_New_Message;
  7936.  
  7937.       else  -- Don't wait for rendezvous
  7938.      -- perform built in test Functions
  7939.      ...
  7940.       end select;
  7941.  
  7942.       Next_Execute := Next_Execute + Task_Period;
  7943.    end loop;
  7944.  
  7945. The following timed entry call may be considered an unacceptable
  7946. implementation if lost communications with the reactor for over 25
  7947. milliseconds results in a critical situation.
  7948.  
  7949. ...
  7950. loop
  7951.  
  7952.    select
  7953.       Reactor.Status(OK);
  7954.  
  7955.    or
  7956.       delay 0.025;
  7957.       -- lost communication for more that 25 milliseconds
  7958.       Emergency_Shutdown;
  7959.    end select;
  7960.  
  7961.    -- process reactor status
  7962.    ...
  7963. end loop;
  7964. ...
  7965.  
  7966. In the following "selective wait with delay" example, the accuracy of the
  7967. coordinate calculation function is bounded by time. For example, the required 
  7968. accuracy cannot be obtained unless Period is within + or - 0.005 seconds. This 
  7969. period cannot be guaranteed because of the inaccuracy of the delay statement. 
  7970.  
  7971. ...
  7972. loop
  7973.  
  7974.    select
  7975.       accept Request_New_Coordinates (X :    out Integer;
  7976.                       Y :    out Integer) do
  7977.      -- copy coordinates to parameters
  7978.      ...
  7979.       end Request_New_Coordinates;
  7980.  
  7981.    or
  7982.       delay Next_Execute - Calendar.Clock;
  7983.    end select;
  7984.  
  7985.    Next_Execute := Next_Execute + Period;
  7986.    -- Read Sensors
  7987.    -- execute coordinate transformations
  7988. end loop;
  7989. ...
  7990.  
  7991. rationale
  7992.  
  7993. Use of these constructs always poses a risk of race conditions. Using them in 
  7994. loops, particularly with poorly chosen task priorities, can have the effect of 
  7995. busy waiting.
  7996.  
  7997. These constructs are very much implementation dependent. For conditional entry
  7998. calls and selective waits with else parts, the Ada Language Reference Manual
  7999. (Department of Defense 1983) does not define "immediately." For timed entry
  8000. calls and selective waits with delay alternatives, implementors may have ideas
  8001. of time that differ from each other and from your own. Like the delay
  8002. statement, the delay alternative on the select construct might wait longer
  8003. than the time required (see Guideline ).
  8004.  
  8005. 6.2.6   Communication Complexity
  8006.  
  8007. guideline
  8008.  
  8009. o       Minimize the number of accept and select statements per task.
  8010.  
  8011. o       Minimize the number of accept statements per entry.
  8012.  
  8013. example
  8014.  
  8015. Use 
  8016.  
  8017. accept A;
  8018. if Mode_1 then
  8019.    -- do one thing
  8020. else  -- Mode_2
  8021.    -- do something different
  8022. end if;
  8023.  
  8024. rather than
  8025.  
  8026. if Mode_1 then
  8027.    accept A;
  8028.    -- do one thing
  8029.  
  8030. else  -- Mode_2
  8031.    accept A;
  8032.    -- do something different
  8033. end if;
  8034.  
  8035. rationale
  8036.  
  8037. This guideline reduces conceptual complexity. Only entries necessary to 
  8038. understand externally observable task behavior should be introduced. If there 
  8039. are several different accept and select statements that do not modify task 
  8040. behavior in a way important to the user of the task, there is unnecessary 
  8041. complexity introduced by the proliferation of select/accept statements. 
  8042. Externally observable behavior important to the task user includes task timing 
  8043. behavior, task rendezvous initiated by the entry calls, prioritization of 
  8044. entries, or data updates (where data is shared between tasks).
  8045.  
  8046. 6.3     TERMINATION
  8047.  
  8048. The ability of tasks to interact with each other using Ada's intertask
  8049. communication features makes it especially important to manage planned or
  8050. unplanned (e.g., in response to a catastrophic exception condition)
  8051. termination in a disciplined way. To do otherwise can lead to a proliferation
  8052. of undesired and unpredictable side effects as a result of the termination of
  8053. a single task.
  8054.  
  8055. 6.3.1   Avoiding Termination
  8056.  
  8057. guideline
  8058.  
  8059. o       Place an exception handler for a rendezvous within the main tasking 
  8060. loop.
  8061.  
  8062. example
  8063.  
  8064. In the following example an exception raised using the primary sensor is used 
  8065. to change Mode to Degraded still allowing execution of the system.
  8066.  
  8067. ...
  8068. loop
  8069.  
  8070.    Recognize_Degraded_Mode:
  8071.       begin
  8072.  
  8073.      if Mode = Primary then
  8074.  
  8075.         select
  8076.            Current_Position_Primary.Request_New_Coordinates
  8077.             (X, Y);
  8078.  
  8079.         or
  8080.            delay 0.25;
  8081.            -- Decide whether to switch modes;
  8082.         end select;
  8083.  
  8084.      else  -- Mode = Degraded
  8085.  
  8086.         Current_Position_Backup.Request_New_Coordinates
  8087.              (X, Y);
  8088.      end if;
  8089.  
  8090.      ...
  8091.       exception
  8092.      when Tasking_Error | Program_Error =>
  8093.         Mode := Degraded;
  8094.       end Recognize_Degraded_Mode;
  8095.  
  8096. end loop;
  8097. ...
  8098.  
  8099. rationale
  8100.  
  8101. Allowing a task to terminate may not support the requirements of the system. 
  8102. Without an exception handler for the rendezvous within the main task loop, the 
  8103. functions of the task may not be performed.
  8104.  
  8105. note
  8106.  
  8107. The use of an exception handler is the only way to guarantee recovery from an
  8108. entry call to an abnormal task. Use of the 'Terminated attribute to test a
  8109. task's availability before making the entry call can introduce a race
  8110. condition where the tested task fails after the test but before the entry call
  8111. (see Guideline ).
  8112.  
  8113. 6.3.2   Normal Termination
  8114.  
  8115. guideline
  8116.  
  8117. o       Do not create non-terminating tasks unintentionally.  
  8118.  
  8119. o       Explicitly shut down tasks dependent on library packages.
  8120.  
  8121. o       Use a select statement rather than an accept statement alone. 
  8122.  
  8123. o       Provide a terminate alternative for every selective wait that does not 
  8124. require an else part or a delay.
  8125.  
  8126. example
  8127.  
  8128. This task will never terminate:
  8129.  
  8130. ---------------------------------------------------------------------
  8131. task body Message_Buffer is
  8132.    ...
  8133.  
  8134. begin  -- Message_Buffer
  8135.    loop
  8136.  
  8137.       select
  8138.      when Head /= Tail => -- Circular buffer not empty
  8139.         accept Retrieve (Value :    out Element) do
  8140.            ...
  8141.         end Retrieve;
  8142.           
  8143.  
  8144.       or
  8145.      when not ((Head  = Lower_Bound and then
  8146.             Tail  = Upper_Bound)    or else
  8147.            (Head /= Lower_Bound and then
  8148.             Tail  = Index'Pred(Head))    )
  8149.          => -- Circular buffer not full
  8150.  
  8151.         accept Store (Value : in     Element);
  8152.       end select;
  8153.    end loop;
  8154.  
  8155. ...
  8156. end Message_Buffer;
  8157. ---------------------------------------------------------------------
  8158.  
  8159. rationale
  8160.  
  8161. A nonterminating task is a task whose body consists of a nonterminating loop
  8162. with no selective wait with terminate, or a task that is dependent on a
  8163. library package. Execution of a subprogram or block containing a task cannot
  8164. complete until the task terminates. Any task that calls a subprogram
  8165. containing a nonterminating task will be delayed indefinitely.
  8166.  
  8167. The effect of unterminated tasks at the end of program execution is undefined.
  8168. A task dependent on a library package cannot be forced to terminate using a
  8169. selective wait construct with terminate alternative and should be terminated
  8170. explicitly during program shutdown. One way to terminate tasks dependent on
  8171. library packages is to provide them with exit entries. Have the main
  8172. subprogram call the exit entry just before it terminates.
  8173.  
  8174. Execution of an accept statement or of a selective wait statement without an 
  8175. else part, a delay, or a terminate alternative cannot proceed if no task ever 
  8176. calls the entry(s) associated with that statement.  This could result in 
  8177. deadlock.  Following this guideline entails programming multiple termination 
  8178. points in the task body.  A reader can easily "know where to look" for the
  8179. normal termination points in a task body.  The termination points are the end 
  8180. of the body's sequence of statements, and alternatives of select statements.
  8181.  
  8182. exceptions
  8183.  
  8184. If you are simulating a cyclic executive, you may need a scheduling task that 
  8185. does not terminate. It has been said that no real-time system should be
  8186. programmed to terminate. This is extreme. Systematic shutdown of many real-time
  8187. systems is a desirable safety feature.
  8188.  
  8189. If you are considering programming a task not to terminate, be certain that it 
  8190. is not a dependent of a block or subprogram from which the task's caller(s) 
  8191. will ever expect to return. Since entire programs can be candidates for reuse 
  8192. (see Chapter ), note that the task (and whatever it depends upon) will not 
  8193. terminate. Also be certain that for any other task that you do wish to 
  8194. terminate, its termination does not await this task's termination. Reread and 
  8195. fully understand paragraph 9.4 of Department of Defense (1983) on "Task
  8196. Dependence - Termination of Tasks."
  8197.  
  8198. 6.3.3   The Abort Statement
  8199.  
  8200. guideline
  8201.  
  8202. o       Avoid using the abort statement.
  8203.  
  8204. example
  8205.  
  8206. If required in the application, provide a task entry for orderly shutdown.
  8207.  
  8208. rationale
  8209.  
  8210. When an abort statement is executed, there is no way to know what the targeted
  8211. task was doing beforehand. Data for which the target task is responsible may
  8212. be left in an inconsistent state. The overall effect on the system of aborting
  8213. a task in such an uncontrolled way requires careful analysis. The system
  8214. design must ensure that all tasks depending on the aborted task can detect the
  8215. termination and respond appropriately.
  8216.  
  8217. Tasks are not aborted until they reach a synchronization point such as 
  8218. beginning or end of elaboration, a delay statement, an accept statement, an 
  8219. entry call, a select statement, task allocation, or the execution of an 
  8220. exception handler. Consequently, the abort statement may not release processor 
  8221. resources as soon as you may expect. It also may not stop a runaway task 
  8222. because the task may be executing an infinite loop containing no 
  8223. synchronization points.
  8224.  
  8225. 6.3.4   Abnormal Termination
  8226.  
  8227. guideline
  8228.  
  8229. o       Place an exception handler for others at the end of a task body.
  8230.  
  8231. o    Have each exception handler at the end of a task body report the
  8232. task's demise.
  8233.  
  8234. example
  8235.  
  8236. This is one of many tasks updating the positions of blips on a radar screen.
  8237. When started, it is given part of the name by which its parent knows it.
  8238. Should it terminate due to an exception, it signals the fact in one of its
  8239. parent's data structures.
  8240.  
  8241. ---------------------------------------------------------------------
  8242. task body Track is
  8243.  
  8244.    My_Index : Track_Index;
  8245.    Neutral  : Boolean    := True;
  8246.  
  8247. begin  -- Track
  8248.  
  8249.    select
  8250.       accept Start (Who_Am_I : in     Track_Index) do
  8251.      My_Index := Who_Am_I;
  8252.       end Start;
  8253.       Neutral := False;
  8254.       ...
  8255.  
  8256.    or
  8257.       terminate;
  8258.    end select;
  8259.  
  8260.    ...
  8261. exception
  8262.    when others =>
  8263.       if not Neutral then
  8264.      Station(My_Index).Status := Dead;
  8265.       end if;
  8266.  
  8267. end Track;
  8268. ---------------------------------------------------------------------
  8269.  
  8270. rationale
  8271.  
  8272. A task will terminate if an exception is raised within it for which it has no 
  8273. handler. In such a case, the exception is not propagated outside of the task 
  8274. (unless it occurs during a rendezvous). The task simply dies with no 
  8275. notification to other tasks in the program. Therefore, providing exception 
  8276. handlers within the task, and especially a handler for others, ensures that a 
  8277. task can regain control after an exception occurs. If the task cannot proceed 
  8278. normally after handling an exception, this affords it the opportunity to shut 
  8279. itself down cleanly and to notify tasks responsible for error recovery 
  8280. necessitated by the abnormal termination of the task.
  8281.  
  8282. note
  8283.  
  8284. Do not use the task status to determine if a rendezvous can be made with the
  8285. task. If task A is dependent on task B and task A checks the status flag
  8286. before it rendezvous with task B, there is a potential that task B fails
  8287. between the status test and the rendezvous. In this case, task A must provide
  8288. an exception handler to handle the Tasking_Error exception raised by the call
  8289. to an entry of an abnormal task (see Guideline ).
  8290.  
  8291. 6.4     SUMMARY
  8292.  
  8293. tasking
  8294.  
  8295. o       Use tasks to model asynchronous entities within the problem domain.
  8296.  
  8297. o       Use tasks to control or synchronize access to tasks or devices.
  8298.  
  8299. o       Use tasks to define concurrent algorithms.
  8300.  
  8301. o       Use anonymous task types for single instances.
  8302.  
  8303. o       Justify the use of dynamically allocated task objects.
  8304.  
  8305. o       Avoid disassociating a dynamic task from all names.
  8306.  
  8307. o       Do not rely on pragma Priority to prioritize the service of entries.
  8308.  
  8309. o       Arrange task bodies in order of their priorities (if possible).
  8310.  
  8311. o       Do not depend on a particular delay being achievable.
  8312.  
  8313. o       Do not use a busy waiting loop instead of a delay.
  8314.  
  8315. o       Design to limit polling to those cases where absolutely necessary.
  8316.  
  8317. o       Do not use knowledge of the execution pattern of tasks to achieve 
  8318. timing requirements.
  8319.  
  8320. communication
  8321.  
  8322. o       Minimize the work performed during a rendezvous.
  8323.  
  8324. o       Minimize the work performed in the selective wait loop of a task.
  8325.  
  8326. o    Provide a handler for exception Program_Error whenever you cannot
  8327. avoid a selective wait statement whose alternates can all be closed.
  8328.  
  8329. o       Make systematic use of handlers for Tasking_Error.
  8330.  
  8331. o       Be prepared to handle exceptions during a rendezvous.
  8332.  
  8333. o       Do not depend on the values of the task attributes 'Callable or 
  8334. 'Terminated.
  8335.  
  8336. o       Do not depend on attributes to avoid Tasking_Error on an entry call. 
  8337.  
  8338. o       Do not depend on the value of the entry attribute 'Count.
  8339.  
  8340. o       Use the rendezvous mechanism, not shared variables, to pass data 
  8341. between tasks.
  8342.  
  8343. o       Do not use shared variables as a task synchronization device.
  8344.  
  8345. o       Do not reference nonlocal variables in a guard.
  8346.  
  8347. o       Use caution with conditional entry calls.
  8348.  
  8349. o       Use caution with selective waits with else parts.
  8350.  
  8351. o       Do not depend upon a particular delay in timed entry calls.
  8352.  
  8353. o       Do not depend upon a particular delay in selective waits with delay 
  8354. alternatives.
  8355.  
  8356. o       Minimize the number of accept and select statements per task.
  8357.  
  8358. o       Minimize the number of accept statements per entry.
  8359.  
  8360. termination
  8361.  
  8362. o       Place an exception handler for a rendezvous within the main tasking 
  8363. loop.
  8364.  
  8365. o       Do not create non-terminating tasks unintentionally.  
  8366.  
  8367. o       Explicitly shut down tasks dependent on library packages.
  8368.  
  8369. o       Use a select statement rather than an accept statement alone. 
  8370.  
  8371. o       Provide a terminate alternative for every selective wait that does not 
  8372. require an else part or a delay.
  8373.  
  8374. o       Avoid using the abort statement.
  8375.  
  8376. o       Place an exception handler for others at the end of a task body.
  8377.  
  8378. o    Have each exception handler at the end of a task body report the
  8379. task's demise.
  8380.  
  8381.  
  8382.  
  8383.  
  8384. CHAPTER 7
  8385. Portability
  8386.  
  8387. Discussions concerning portability usually concentrate on the differences in
  8388. computer systems. But the development and runtime environment may also change:
  8389.  
  8390. portability (software). The ease with which software can be transferred from 
  8391. one computer system or environment to another (IEEE Dictionary 1984).
  8392.  
  8393. And most portability problems are not pure language issues. Portability 
  8394. involves hardware (byte order, device IO); software (utility libraries, 
  8395. operating systems, runtime libraries). This section will not address these 
  8396. challenging design issues.
  8397.  
  8398. This section does identify the more common portability problems that are
  8399. specific to Ada when moving from one platform or compiler to another. It also
  8400. suggests ways that non-portable code can be isolated. By using the
  8401. implementation hiding features of Ada, the cost of porting can be
  8402. significantly reduced.
  8403.  
  8404. In fact, many language portability issues are solved by the strict definition
  8405. of the Ada language itself. In most programming languages, different dialects
  8406. are prevalent as vendors extend or dilute a language for various reasons:
  8407. conformance to a programming environment; or features for a particular
  8408. application domain. The Ada Compiler Validation Capability (ACVC) was
  8409. developed by the U.S. Department of Defense at the Ada Validation Facility,
  8410. ASD/SIDL, Wright-Patterson Air Force Base to ensure that implementors strictly
  8411. adhered to the Ada standard.
  8412.  
  8413. As part of the strict definition of Ada, certain constructs are defined to be
  8414. erroneous and the effect of executing an erroneous construct is unpredictable.
  8415. Therefore erroneous constructs are obviously not portable. Erroneous
  8416. constructs are discussed in Guideline 5.9, and are not repeated in this
  8417. chapter.
  8418.  
  8419. Most programmers new to the language expect Ada to eliminate all portability
  8420. problems; it definitely does not. Certain areas of Ada are not yet covered by
  8421. validation. The definition of Ada leave certain details to the implementor.
  8422. The compiler implementor's choices with respect to these details affect
  8423. portability.
  8424.  
  8425. There are some general principles to enhancing portability exemplified by many 
  8426. of the guidelines in this chapter. They are:
  8427.  
  8428. o       Recognize those Ada constructs that may adversely affect portability.
  8429.  
  8430. o       Avoid the use of these constructs where possible.
  8431.  
  8432. o    Localize and encapsulate nonportable features of a program if their
  8433. use is essential.
  8434.  
  8435. o       Highlight the use of constructs that may cause portability problems.
  8436.  
  8437. These guidelines cannot be applied thoughtlessly. Many of them involve a 
  8438. detailed understanding of the Ada model and its implementation. In many cases, 
  8439. you will have to make carefully considered tradeoffs between efficiency and 
  8440. portability. Reading this chapter should improve your insight into the 
  8441. tradeoffs involved.
  8442.  
  8443. The material in this chapter was largely acquired from three sources: the Ada 
  8444. Run Time Environment Working Group (ARTEWG) Catalogue of Ada Run Time 
  8445. Implementation Dependencies (ARTEWG 1986); the Nissen and Wallis book on 
  8446. Portability and Style in Ada (Nissen and Wallis 1984); and a paper written for 
  8447. the U.S. Air Force by SofTech on Ada Portability Guidelines (Pappas 1985). The 
  8448. last of these sources (Pappas 1985) encompasses the other two and provides an 
  8449. in depth explanation of the issues, numerous examples, and techniques for 
  8450. minimizing portability problems. Conti (1987) is a valuable reference for 
  8451. understanding the latitude allowed for implementors of Ada and the criteria 
  8452. often used to make decisions.
  8453.  
  8454. This chapter's purpose is to provide a summary of portability issues in the
  8455. guideline format of this book. The chapter does not include all issues
  8456. identified in the references, but only the most significant. For an in-depth
  8457. presentation, see Pappas (1985). A few additional guidelines are presented
  8458. here and others are elaborated upon where applicable. For further reading on
  8459. Ada I/O portability issues, see Matthews (1987), Griest (1989), and CECOM
  8460. (1989).
  8461.  
  8462. Some of the guidelines in this chapter cross reference and place stricter 
  8463. constraints on other guidelines in this book. These constraints apply when 
  8464. portability is being emphasized.
  8465.  
  8466. 7.1     FUNDAMENTALS
  8467.  
  8468. This section introduces some generally applicable principles of writing 
  8469. portable Ada programs. It includes guidelines about the assumptions you should 
  8470. make with respect to a number of Ada features and their implementations and 
  8471. guidelines about the use of other Ada features to ensure maximum portability.
  8472.  
  8473. 7.1.1   Global Assumptions
  8474.  
  8475. guideline
  8476.  
  8477. o       Make considered assumptions about the support provided for the 
  8478. following on potential target platforms:
  8479.  
  8480. -       Number of bits available for type Integer (range constraints).
  8481.  
  8482. -       Number of decimal digits of precision available for floating point 
  8483. types.
  8484.  
  8485. -       Number of bits available for fixed-point types (delta and range
  8486. constraints).
  8487.  
  8488. -       Number of characters per line of source text.
  8489.  
  8490. -       Number of bits for Universal_Integer expressions.
  8491.  
  8492. -       Number of seconds for the range of Duration.
  8493.  
  8494. -       Number of milliseconds for Duration'Small. 
  8495.  
  8496. instantiation
  8497.  
  8498. These are minimum values (or minimum precision in the case of Duration'Small) 
  8499. that a project or application might assume that an implementation provides. 
  8500. There is no guarantee that a given implementation provides more than the 
  8501. minimum, so these would be treated by the project or application as maximum 
  8502. values also.
  8503.  
  8504. -       16 bits available for type Integer (-2**15 .. 2**15 - 1).
  8505.  
  8506. -       6 decimal digits of precision available for floating point types.
  8507.  
  8508. -       32 bits available for fixed-point types.
  8509.  
  8510. -       72 characters per line of source text.
  8511.  
  8512. -       16 bits for Universal_Integer expressions.
  8513.  
  8514. -       -86_400 .. 86_400 seconds (1 day) for the range of Duration (as 
  8515. specified in 9.6 (4) of Department of Defense 1983))
  8516.  
  8517. -       20 milliseconds for Duration'Small (as specified in 9.6 (4) of 
  8518. Department of Defense 1983)).
  8519.  
  8520. rationale
  8521.  
  8522. Some assumptions must be made with respect to certain implementation dependent 
  8523. values. The exact values assumed should cover the majority of the target 
  8524. equipment of interest. Choosing the lowest common denominator for values 
  8525. improves portability.
  8526.  
  8527. note
  8528.  
  8529. Of the microcomputers currently available for incorporation within embedded
  8530. systems, 16-bit and 32-bit processors are prevalent. Although 4-bit and 8-bit
  8531. machines are still available, their limited memory addressing capabilities
  8532. make them unsuited to support Ada programs of any size. Using current
  8533. representation schemes, 6 decimal digits of floating point accuracy implies a
  8534. representation mantissa at least 21 bits wide, leaving 11 bits for exponent
  8535. and sign within a 32-bit representation. This correlates with the data widths
  8536. of floating point hardware currently available for the embedded systems
  8537. market. A 32-bit minimum on fixed-point numbers correlates with the accuracy
  8538. and storage requirements of floating point numbers.
  8539.  
  8540. The 72-column limit on source lines in the example is an unfortunate hold-over
  8541. from the days of Hollerith punch cards with sequence numbers. There may still 
  8542. be machinery and software used in manipulating source code that are bound to 
  8543. assumptions about this maximum line length. The 16-bit example for
  8544. Universal_Integer expressions matches that for Integer storage.
  8545.  
  8546. The values for the range and accuracy of values of the predefined type
  8547. Duration are the limits expressed in the Ada Language Reference Manual
  8548. (Department of Defense 1983, w 9.6). You should not expect an implementation
  8549. to provide a wider range or a finer granularity.
  8550.  
  8551. 7.1.2   Actual Limits
  8552.  
  8553. guideline
  8554.  
  8555. o       Don't implicitly use an implementation limit.
  8556.  
  8557. rationale
  8558.  
  8559. The Ada model may not match exactly with the underlying hardware, so some 
  8560. compromises may have been made in the implementation. Check to see if they 
  8561. could affect your program. Particular implementations may do "better" than the
  8562. Ada model requires while some others may be just minimally acceptable. 
  8563. Arithmetic is generally implemented with a precision higher than the storage 
  8564. capacity (this is implied by the Ada type model for floating point). Different 
  8565. implementations may behave differently on the same underlying hardware.
  8566.  
  8567. 7.1.3   Comments
  8568.  
  8569. guideline
  8570.  
  8571. o       Use highlighting comments for each package, subprogram and task where 
  8572. any nonportable features are present. 
  8573.  
  8574. o       For each nonportable feature employed, describe the expectations for 
  8575. that feature.
  8576.  
  8577. example
  8578.  
  8579. ------------------------------------------------------------------------
  8580. package Memory_Mapped_IO is
  8581.  
  8582.    -- WARNING - This package is implementation specific.
  8583.    -- It uses absolute memory addresses to interface with the I/O
  8584.    -- system. It assumes a particular printer's line length.
  8585.    -- Change memory mapping and printer details when porting.
  8586.  
  8587.    Printer_Line_Length : constant := 132;
  8588.  
  8589.    type Data is array (1 .. Printer_Line_Length) of Character;
  8590.  
  8591.    procedure Write_Line (Line : in     Data);
  8592.  
  8593. end Memory_Mapped_IO;
  8594.  
  8595. ------------------------------------------------------------------------
  8596. with System;
  8597. package body Memory_Mapped_IO is
  8598.  
  8599.    ---------------------------------------------------------------------
  8600.    procedure Write_Line (Line : in     Data) is
  8601.  
  8602.       Buffer : Data;
  8603.       for Buffer use at System.Physical_Address(16#200#);
  8604.  
  8605.    begin  -- Write_Line
  8606.        -- perform output operation through specific memory locations.
  8607.        ...
  8608.    end Write_Line;
  8609.    ---------------------------------------------------------------------
  8610.  
  8611. end Memory_Mapped_IO;
  8612. ------------------------------------------------------------------------
  8613.  
  8614. rationale
  8615.  
  8616. Explicitly commenting each breach of portability will raise its visibility and 
  8617. aid in the porting process. A description of the non-portable feature's
  8618. expectations covers the common case where vendor documentation of the original 
  8619. implementation is not available to the person performing the porting process.
  8620.  
  8621. 7.1.4   Main Subprogram
  8622.  
  8623. guideline
  8624.  
  8625. o       Use only a parameterless procedure as the main program.
  8626.  
  8627. rationale
  8628.  
  8629. The Ada Language Reference Manual (Department of Defense 1983) places very few 
  8630. requirements on the main subprogram.  Assume the simplest case will increase 
  8631. portability. That is, assume you may only use a parameterless procedure as a 
  8632. main program.
  8633.  
  8634. Some operating systems are capable of acquiring and interpreting returned
  8635. integer values near zero from a function, but many others cannot. Further,
  8636. many real-time, embedded systems will not be designed to terminate, so a
  8637. function or a procedure having parameters with modes out or in out will be
  8638. inappropriate to such applications.
  8639.  
  8640. This leaves procedures with in parameters. Although some operating systems can
  8641. pass parameters in to a program as it starts, others cannot. Also, an
  8642. implementation may not be able to perform type checking on such parameters
  8643. even if the surrounding environment is capable of providing them.
  8644.  
  8645. note
  8646.  
  8647. Real-time, embedded applications may not have an "operator" initiating the
  8648. program to supply the parameters, in which case it would be more appropriate
  8649. for the program to have been compiled with a package containing the
  8650. appropriate constant values or for the program to read the necessary values
  8651. from switch settings or a downloaded auxiliary file. In any case, the
  8652. variation in surrounding initiating environments is far too great to depend
  8653. upon the kind of last-minute (program) parameterization implied by
  8654. (subprogram) parameters to the main subprogram.
  8655.  
  8656. 7.1.5   Encapsulating Implementation Dependencies
  8657.  
  8658. guideline
  8659.  
  8660. o       Create packages specifically designed to isolate hardware and 
  8661. implementation dependencies and designed so that their specification will not 
  8662. change when porting.
  8663.  
  8664. o       Clearly indicate the objectives if machine or solution efficiency is 
  8665. the reason for hardware or implementation dependent code.
  8666.  
  8667. o       For the packages that hide implementation dependencies, maintain 
  8668. different package bodies for different target environments.
  8669.  
  8670. o       Isolate interrupt receiving tasks into implementation dependent 
  8671. packages.
  8672.  
  8673. example
  8674.  
  8675. See Guideline .
  8676.  
  8677. rationale
  8678.  
  8679. Encapsulating hardware and implementation dependencies in a package allows the
  8680. remainder of the code to ignore them and thus to be fully portable. It also
  8681. localizes the dependencies, making it clear exactly which parts of the code
  8682. may need to change when porting the program.
  8683.  
  8684. Some implementation-dependent features may be used to achieve particular
  8685. performance or efficiency objectives. Commenting these objectives ensures that 
  8686. the programmer can find an appropriate way to achieve them when porting to a 
  8687. different implementation, or explicitly recognize that they cannot be achieved.
  8688.  
  8689. Interrupt entries are implementation-dependent features that may not be
  8690. supported (e.g., VAX Ada uses pragmas to assign system traps to "normal"
  8691. rendezvous). However, interrupt entries cannot be avoided in most embedded 
  8692. real-time systems and it is reasonable to assume that they are supported by an
  8693. Ada implementation. The value for an interrupt is implementation-defined.
  8694. Isolate it.
  8695.  
  8696. note
  8697.  
  8698. Ada can be used to write machine-dependent programs that take advantage of an
  8699. implementation in a manner consistent with the Ada model, but which make 
  8700. particular choices where Ada allows implementation freedom. These machine 
  8701. dependencies should be treated in the same way as any other implementation 
  8702. dependent features of the code.
  8703.  
  8704. 7.1.6   Implementation-Added Features
  8705.  
  8706. guideline
  8707.  
  8708. o       Avoid the use of vendor supplied packages.
  8709.  
  8710. o    Avoid the use of features added to the predefined packages that are
  8711. not specified in the language definition.
  8712.  
  8713. rationale
  8714.  
  8715. Vendor-added features are not likely to be provided by other implementations.
  8716. Even if a majority of vendors eventually provide similar additional features,
  8717. they are unlikely to have identical formulations. Indeed, different vendors
  8718. may use the same formulation for (semantically) entirely different features.
  8719.  
  8720. exceptions
  8721.  
  8722. There are many types of applications that require the use of these features.
  8723. Examples include: multilingual systems that standardize on a vendor's file
  8724. system, applications that are closely integrated with vendor products (i.e.,
  8725. user interfaces), and embedded systems for performance reasons. Isolate the
  8726. use of these features into packages.
  8727.  
  8728. 7.2     NUMERIC TYPES AND EXPRESSIONS
  8729.  
  8730. A great deal of care was taken with the design of the Ada features related to 
  8731. numeric computations to ensure that the language could be used in embedded 
  8732. systems and mathematical applications where precision was important. As far as 
  8733. possible, these features were made portable. However, there is an inevitable 
  8734. tradeoff between maximally exploiting the available precision of numeric 
  8735. computation on a particular machine and maximizing the portability of Ada 
  8736. numeric constructs. This means that these Ada features, particularly numeric 
  8737. types and expressions, must be used with great care if full portability of the 
  8738. resulting program is to be guaranteed.
  8739.  
  8740. 7.2.1   Predefined Numeric Types
  8741.  
  8742. guideline
  8743.  
  8744. o    Do not use the predefined numeric types in package Standard. Use range
  8745. and digits declarations and let the implementation do the derivation
  8746. implicitly from the predefined types.
  8747.  
  8748. o       For programs that require greater accuracy than that provided by the 
  8749. global assumptions, define a package that declares a private type and 
  8750. operations as needed; see Pappas (1985) for a full explanation and examples.
  8751.  
  8752. example
  8753.  
  8754. The second and third examples below are not representable as subranges of 
  8755. Integer on a machine with a 16-bit word. The first example below allows a
  8756. compiler to choose a multiword representation if necessary.
  8757.  
  8758. use
  8759.  
  8760. type    Second_Of_Day is             range 0 .. 86_400;
  8761.  
  8762. rather than
  8763.  
  8764. type    Second_Of_Day is new Integer range 1 .. 86_400;
  8765.  
  8766. or
  8767.  
  8768. subtype Second_Of_Day is     Integer range 1 .. 86_400;
  8769.  
  8770. rationale
  8771.  
  8772. An implementor is free to define the range of the predefined numeric types.
  8773. Porting code from an implementation with greater accuracy to one of lesser is
  8774. a time consuming and error-prone process. Many of the errors are not reported
  8775. until run-time.
  8776.  
  8777. This applies to more than just numerical computation. An easy-to-overlook
  8778. instance of this problem occurs if you neglect to use explicitly declared
  8779. types for integer discrete ranges (array sizes, loop ranges, etc.) (see
  8780. Guidelines and ). If you do not provide an explicit type when specifying index
  8781. constraints and other discrete ranges, a predefined integer type is assumed.
  8782.  
  8783. exceptions
  8784.  
  8785. Any indexing into the predefined String type requires that the index at least 
  8786. be a subtype of the predefined Integer type.  The predefined packages also use 
  8787. the various predefined types.
  8788.  
  8789. note
  8790.  
  8791. There is an alternative which this guideline permits.  As Guideline suggests,
  8792. implementation dependencies can be encapsulated in packages intended for that
  8793. purpose.  This could include the definition of a 32-bit integer type.  It
  8794. would then be possible to derive additional types from that 32-bit type.
  8795.  
  8796. 7.2.2   Ada Model
  8797.  
  8798. guideline
  8799.  
  8800. o       Know the Ada model for floating point types and arithmetic.
  8801.  
  8802. rationale
  8803.  
  8804. Declarations of Ada floating point types give users control over both the
  8805. representation and arithmetic used in floating point operations. Portable
  8806. properties of Ada programs are derived from the models for floating point
  8807. numbers of the subtype and the corresponding safe numbers. The relative
  8808. spacing and range of values in a type are determined by the declaration.
  8809. Attributes can be used to specify the transportable properties of an Ada
  8810. floating point type.
  8811.  
  8812. 7.2.3   Analysis
  8813.  
  8814. guideline
  8815.  
  8816. o       Carefully analyze what accuracy and precision you really need.
  8817.  
  8818. rationale
  8819.  
  8820. Floating point calculations are done with the equivalent of the 
  8821. implementation's predefined floating point types. The effect of extra "guard"
  8822. digits in internal computations can sometimes lower the number of digits that 
  8823. must be specified in an Ada declaration. This may not be consistent over 
  8824. implementations where the program is intended to be run. It may also lead to 
  8825. the false conclusion that the declared types are sufficient for the accuracy 
  8826. required.
  8827.  
  8828. The numeric type declarations should be chosen to satisfy the lowest precision 
  8829. (smallest number of digits) that will provide the required accuracy. Careful 
  8830. analysis will be necessary to show that the declarations are adequate.
  8831.  
  8832. 7.2.4   Accuracy Constraints
  8833.  
  8834. guideline
  8835.  
  8836. o       Do not press the accuracy limits of the machine(s).
  8837.  
  8838. rationale
  8839.  
  8840. The Ada floating point model is intended to facilitate program portability, 
  8841. which is often at the expense of efficiency in using the underlying machine 
  8842. arithmetic. Just because two different machines use the same number of digits 
  8843. in the mantissa of a floating point number does not imply they will have the 
  8844. same arithmetic properties. Some Ada implementations may give slightly better 
  8845. accuracy than required by Ada because they make efficient use of the machine. 
  8846. Do not write programs that depend on this.
  8847.  
  8848. 7.2.5   Comments
  8849.  
  8850. guideline
  8851.  
  8852. o       Comment the analysis and derivation of the numerical aspects of a 
  8853. program.
  8854.  
  8855. rationale
  8856.  
  8857. Decisions and background about why certain precisions are required in a
  8858. program are important to program revision or porting. The underlying numerical
  8859. analysis leading to the program should be commented.
  8860.  
  8861. 7.2.6   Precision of Constants
  8862.  
  8863. guideline
  8864.  
  8865. o       Use named numbers or universal real expressions rather than constants 
  8866. of any particular type.
  8867.  
  8868. rationale
  8869.  
  8870. For a given radix (number base), there is a loss of accuracy for some rational
  8871. and all irrational numbers when represented by a finite sequence of digits.
  8872. Ada has named numbers and expressions of type universal_real that provide
  8873. maximal accuracy of representation in the source program. These numbers and
  8874. expressions are converted to finite representations at compile time. By using
  8875. universal real expressions and numbers, the programmer can automatically delay
  8876. the conversion to machine types until the point where it can be done with the
  8877. minimum loss of accuracy.
  8878.  
  8879. note
  8880.  
  8881. See also Guideline .
  8882.  
  8883. 7.2.7   Subexpression Evaluation
  8884.  
  8885. guideline
  8886.  
  8887. o       Anticipate values of subexpressions to avoid exceeding the range of 
  8888. their type. Use derived types, subtypes, factoring, and range constraints on 
  8889. numeric types as described in Guidelines , , and .
  8890.  
  8891. rationale
  8892.  
  8893. The Ada language does not require that an implementation perform range checks 
  8894. on subexpressions within an expression. Even if the implementation on your 
  8895. program's current target does not perform these checks, your program may be 
  8896. ported to an implementation that does.
  8897.  
  8898. 7.2.8   Relational Tests
  8899.  
  8900. guideline
  8901.  
  8902. o    Use <= and >= to do relational tests on real valued arguments,
  8903. avoiding the <, >, =, and /= operations.
  8904.  
  8905. o       Use values of type attributes in comparisons and checking for small 
  8906. values.
  8907.  
  8908. example
  8909.  
  8910. The following examples test for (1) absolute "equality" in storage, (2)
  8911. absolute "equality" in computation, (3) relative "equality" in storage, and (4)
  8912. relative "equality" in computation.
  8913.  
  8914. abs (X - Y) <= Float_Type'Small                -- (1)
  8915.  
  8916. abs (X - Y) <= Float_Type'Base'Small           -- (2)
  8917.  
  8918. abs (X - Y) <= abs X * Float_Type'Epsilon      -- (3)
  8919.  
  8920. abs (X - Y) <= abs X * Float_Type'Base'Epsilon -- (4)
  8921.  
  8922. And specifically for "equality" to zero:
  8923.  
  8924. abs X <= Float_Type'Small                      -- (1)
  8925.  
  8926. abs X <= Float_Type'Base'Small                 -- (2)
  8927.  
  8928. abs X <= abs X * Float_Type'Epsilon            -- (3)
  8929.  
  8930. abs X <= abs X * Float_Type'Base'Epsilon       -- (4)
  8931.  
  8932. rationale
  8933.  
  8934. Strict relational comparisons ( <, >, =, /= ) are a general problem in real
  8935. valued computations. Because of the way Ada comparisons are defined in terms
  8936. of model intervals, it is possible for the values of the Ada comparisons A < B
  8937. and A = B to depend on the implementation, while A <= B evaluates uniformly
  8938. across implementations. Note that for real values in Ada, "A <= B" is not the
  8939. same as "not (A > B)".  Further explanation can be found in Cohen (1986)
  8940. pp.227-233.
  8941.  
  8942. Type attributes are the primary means of symbolically accessing the
  8943. implementation of the Ada numeric model. When the characteristics of the model
  8944. numbers are accessed symbolically, the source code is portable. The
  8945. appropriate model numbers of any implementation will then be used by the
  8946. generated code.
  8947.  
  8948. Although zero is technically not a special case, it is often overlooked
  8949. because it looks like the simplest and, therefore, safest case.  But in
  8950. reality, each time comparisons involve small values, evaluate the situation to
  8951. determine which technique is appropriate.
  8952.  
  8953. note
  8954.  
  8955. Regardless of language, real valued computations have inaccuracy.  That the 
  8956. corresponding mathematical operations have algebraic properties usually 
  8957. introduces some confusion.  This guideline explains how Ada deals with the 
  8958. problem that most languages face.
  8959.  
  8960. 7.3     STORAGE CONTROL
  8961.  
  8962. The management of dynamic storage can vary between Ada environments. In fact, 
  8963. some environments do not provide any deallocation.  Ada's storage control 
  8964. mechanisms are too implementation dependent to be considered portable.
  8965.  
  8966. 7.3.1   Representation Clause
  8967.  
  8968. guideline
  8969.  
  8970. o        Do not use a representation clause to specify number of storage units.
  8971.  
  8972. rationale
  8973.  
  8974. The meaning of the 'Storage_Size attribute is ambiguous; so, specifying a
  8975. particular value will not improve portability.  It may or may not include
  8976. space allocated for parameters, data, etc.  Save the use of this feature for
  8977. designs that must depend on a particular vendor's implementation.
  8978.  
  8979. note
  8980.  
  8981. During a porting activity, it can be assumed that any occurrence of storage 
  8982. specification indicates an implementation dependency that must be redesigned.
  8983.  
  8984. 7.4     TASKING
  8985.  
  8986. The definition of tasking in the Ada language leaves many characteristics of 
  8987. the tasking model up to the implementor. This allows a vendor to make 
  8988. appropriate tradeoffs for the intended application domain, but it also 
  8989. diminishes the portability of designs and code employing the tasking features. 
  8990. In some respects this diminished portability is an inherent characteristic of 
  8991. concurrency approaches (see Nissen and Wallis 1984, 37). 
  8992.  
  8993. A discussion of Ada tasking dependencies when employed in a distributed target 
  8994. environment is beyond the scope of this book. For example, multi-processor task
  8995. scheduling, interprocessor rendezvous, and the distributed sense of time 
  8996. through package Calendar are all subject to differences between 
  8997. implementations. For more information, Nissen and Wallis (1984) and ARTEWG 
  8998. (1986) touch on these issues and (Volz et al. 1985) is one of many research 
  8999. articles available.
  9000.  
  9001. 7.4.1   Task Activation Order
  9002.  
  9003. guideline
  9004.  
  9005. o       Do not depend on the order in which task objects are activated when 
  9006. declared in the same declarative list.
  9007.  
  9008. rationale
  9009.  
  9010. The order is left undefined in the Ada Language Reference Manual (Department
  9011. of Defense 1983).
  9012.  
  9013. 7.4.2   Delay Statements
  9014.  
  9015. guideline
  9016.  
  9017. o    Do not depend on a particular delay being achievable (Nissen and
  9018. Wallis 1984).
  9019.  
  9020. o       Never use a busy waiting loop instead of a delay.
  9021.  
  9022. o       Design to limit polling to those cases where it is absolutely 
  9023. necessary.
  9024.  
  9025. o    Never use knowledge of the execution pattern of tasks to achieve
  9026. timing requirements.
  9027.  
  9028. rationale
  9029.  
  9030. The rationale for this appears in Guideline . In addition, the treatment of
  9031. delay statements varies from implementation to implementation thereby
  9032. hindering portability.
  9033.  
  9034. 7.4.3   Package Calendar, Type Duration, and System.Tick
  9035.  
  9036. guideline
  9037.  
  9038. o    Do not assume a correlation between System.Tick and package Calendar
  9039. or type Duration (see Guideline ).
  9040.  
  9041. rationale
  9042.  
  9043. Such a correlation is not required, although it may exist in some 
  9044. implementations.
  9045.  
  9046. 7.4.4   Select Statement Evaluation Order
  9047.  
  9048. guideline
  9049.  
  9050. o       Do not depend on the order in which guard conditions are evaluated or 
  9051. on the algorithm for choosing among several open select alternatives.
  9052.  
  9053. rationale
  9054.  
  9055. The language does not define the order of these conditions, so assume that
  9056. they are arbitrary.
  9057.  
  9058. 7.4.5   Task Scheduling Algorithm
  9059.  
  9060. guideline
  9061.  
  9062. o       Do not assume that tasks execute uninterrupted until they reach a 
  9063. synchronization point.
  9064.  
  9065. o       Use pragma Priority to distinguish general levels of importance only 
  9066. (see Guideline ).
  9067.  
  9068. rationale
  9069.  
  9070. The Ada tasking model requires that tasks be synchronized only through the
  9071. explicit means provided in the language (i.e., rendezvous, task dependence,
  9072. pragma Shared). The scheduling algorithm is not defined by the language and
  9073. may vary from time sliced to preemptive priority. Some implementations (e.g.,
  9074. VAX Ada) provide several choices that a user may select for the application.
  9075.  
  9076. note
  9077.  
  9078. The number of priorities may vary between implementations. In addition, the 
  9079. manner in which tasks of the same priority are handled may vary between 
  9080. implementations even if the implementations use the same general scheduling 
  9081. algorithm.
  9082.  
  9083. exceptions
  9084.  
  9085. In real-time systems it is often necessary to tightly control the tasking
  9086. algorithm to obtain the required performance. For example, avionics systems
  9087. are frequently driven by cyclic events with limited asynchronous
  9088. interruptions. A nonpreemptive tasking model is traditionally used to obtain
  9089. the greatest performance in these applications. Cyclic executives can be
  9090. programmed in Ada, as can a progression of scheduling schemes from cyclic
  9091. through multiple-frame-rate to full asynchrony (MacLaren 1980) although an
  9092. external clock is usually required.
  9093.  
  9094. 7.4.6   Abort
  9095.  
  9096. guideline
  9097.  
  9098. o       Avoid using the abort statement.
  9099.  
  9100. rationale
  9101.  
  9102. The rationale for this appears in Guideline . In addition, treatment of the 
  9103. abort statement varies from implementation to implementation thereby hindering 
  9104. portability.
  9105.  
  9106. 7.4.7   Shared Variables and Pragma Shared
  9107.  
  9108. guideline
  9109.  
  9110. o       Do not share variables. 
  9111.  
  9112. o       Have tasks communicate through the rendezvous mechanism.
  9113.  
  9114. o       Do not use shared variables as a task synchronization device.
  9115.  
  9116. o       Use pragma Shared only when you are forced to by run time system 
  9117. deficiencies.
  9118.  
  9119. rationale
  9120.  
  9121. The rationale for this appears in Guideline . In addition, the treatment of
  9122. shared variables varies from implementation to implementation thereby
  9123. hindering portability.
  9124.  
  9125. 7.5     EXCEPTIONS
  9126.  
  9127. Care must be exercised using predefined exceptions since aspects of their 
  9128. treatment may vary between implementations. Implementation-defined exceptions
  9129. must, of course, be avoided.  Other guidelines concerning exceptions can be 
  9130. found in Guidelines  and .
  9131.  
  9132. 7.5.1   Predefined Exceptions
  9133.  
  9134. guideline
  9135.  
  9136. o    Do not depend on the exact locations at which predefined exceptions
  9137. are raised.
  9138.  
  9139. rationale
  9140.  
  9141. The Ada Language Reference Manual (Department of Defense 1983) states that
  9142. among implementations, a predefined exception for the same cause may be raised
  9143. from different locations. You will not be able to discriminate between the
  9144. exceptions. Further, each of the predefined exceptions is associated with a
  9145. variety of conditions. Any exception handler written for a predefined
  9146. exception must be prepared to deal with any of these conditions.
  9147.  
  9148. 7.5.2   Constraint_Error and Numeric_Error
  9149.  
  9150. guideline
  9151.  
  9152. o       Catch Numeric_Error exceptions with a Numeric_Error | Constraint_Error 
  9153. exception handler.
  9154.  
  9155. o       Do not use a separate exception handler for Numeric_Error and 
  9156. Constraint_Error.
  9157.  
  9158. rationale
  9159.  
  9160. In cases where Numeric_Error may be raised, an implementation is allowed to
  9161. raise Constraint_Error instead.  In fact, there is no requirement that an
  9162. implementation raise the same exception under the same circumstances.  It is
  9163. not enough to replace the Numeric_Error exception with a Constraint_Error.
  9164. Either one may be raised; and if Numeric_Error is raised, it will not be
  9165. caught with a simple Constraint_Error exception handler.
  9166.  
  9167. 7.5.3   Implementation-Defined Exceptions
  9168.  
  9169. guideline
  9170.  
  9171. o       Do not raise implementation-defined exceptions.
  9172.  
  9173. o       Convert implementation defined exceptions within interface packages to 
  9174. visible user-defined exceptions.
  9175.  
  9176. rationale
  9177.  
  9178. No exception defined by an implementation can be guaranteed to be portable to 
  9179. other implementations whether or not they are from the same vendor. Not only 
  9180. may the names be different, but the range of conditions triggering the 
  9181. exceptions may be different also.
  9182.  
  9183. If you create interface packages for the implementation-specific portions of
  9184. your program, those packages can catch or recognize implementation specific
  9185. exceptions and convert them into user-defined exceptions that have been
  9186. declared in the specification.  Do not allow yourself to be forced to find and
  9187. change the name of every handler you have written for these exceptions when
  9188. the program is ported.
  9189.  
  9190. 7.6     REPRESENTATION CLAUSES AND IMPLEMENTATION-
  9191.     DEPENDENT FEATURES
  9192.  
  9193. Ada provides many implementation-dependent features that permit greater
  9194. control over and interaction with the underlying hardware architecture than is
  9195. normally provided by a high-order language. These mechanisms are intended to
  9196. assist in systems programming and real-time programming to obtain greater
  9197. efficiency (e.g., specific size layout of variables through representation
  9198. clauses) and direct hardware interaction (e.g., interrupt entries) without
  9199. having to resort to assembly level programming.
  9200.  
  9201. Given the objectives for these features, it is not surprising that you must
  9202. usually pay a significant price in portability to use them. In general, where
  9203. portability is the main objective, do not use these features. When you must
  9204. use these features, encapsulate them in packages well-commented as interfacing
  9205. to the particular target environment. This section identifies the various
  9206. features and their recommended use with respect to portability.
  9207.  
  9208. 7.6.1   Representation Clauses
  9209.  
  9210. guideline
  9211.  
  9212. o    Use algorithms that do not depend on the representation of the data
  9213. and therefore do not need representation clauses.
  9214.  
  9215. o       Use representation clauses when accessing interface data or when a 
  9216. specific representation is needed to implement a design.
  9217.  
  9218. rationale
  9219.  
  9220. In many cases, it is easy to use representation clauses to implement an
  9221. algorithm, even when it is not necessary.  There is also a tendency to
  9222. document the original programmer's assumptions about the representation for
  9223. future reference.  But there is no guarantee that another implementation will
  9224. support the representation chosen.  Unnecessary representation clauses also
  9225. confuse porting or maintenance efforts which must assume that the programmer
  9226. depends on the documented representation.
  9227.  
  9228. Interfaces to non-Ada systems and external devices are the most common 
  9229. situations where a representation clause is needed.  Uses of pragma Interface 
  9230. and address clauses should be evaluated during design and porting to determine 
  9231. whether a representation clause is needed.
  9232.  
  9233. note
  9234.  
  9235. During a porting effort, all representation clauses can be evaluated as either 
  9236. design artifacts or specifications for accessing interface data that might 
  9237. change with a new implementation.
  9238.  
  9239. 7.6.2   Package System
  9240.  
  9241. guideline
  9242.  
  9243. o    Avoid using package System constants except in attempting to
  9244. generalize other machine dependent constructs.
  9245.  
  9246. rationale
  9247.  
  9248. Since the values in this package are implementation-provided, unexpected
  9249. effects can result from their use.
  9250.  
  9251. exceptions
  9252.  
  9253. Do use package System constants to parameterize other implementation-dependent
  9254. features (see Pappas [1985] w13.7.1).
  9255.  
  9256. 7.6.3   Machine Code Inserts
  9257.  
  9258. guideline
  9259.  
  9260. o       Avoid machine code inserts.
  9261.  
  9262. rationale
  9263.  
  9264. Appendix C (of Department of Defense 1983) suggests that the package 
  9265. implementing machine code inserts is optional.  Additionally, it is not 
  9266. standardized so that machine code inserts are most likely not portable.  In 
  9267. fact, it is possible that two different vendors' syntax will differ for an 
  9268. identical target and differences in lower-level details such as register
  9269. conventions will hinder portability.
  9270.  
  9271. exceptions
  9272.  
  9273. If machine code inserts must be used to meet another project requirement, 
  9274. recognize the portability decreasing effects.
  9275.  
  9276. In the declarative region of the body of the routine where the machine code 
  9277. insert is being used, insert comments explaining what function the insert 
  9278. provides, and (especially) why the insert is necessary. Comment the necessity 
  9279. of using machine code inserts by delineating what went wrong with attempts to 
  9280. use other higher-level constructs.
  9281.  
  9282. 7.6.4   Interfacing Foreign Languages
  9283.  
  9284. guideline
  9285.  
  9286. o       Avoid interfacing Ada with other languages. 
  9287.  
  9288. o       Isolate all subprograms employing pragma Interface to 
  9289. implementation-dependent (interface) package bodies.
  9290.  
  9291. rationale
  9292.  
  9293. The problems with employing pragma Interface are complex. These problems
  9294. include pragma syntax differences, conventions for linking/binding Ada to
  9295. other languages, and mapping Ada variables to foreign language variables.  By
  9296. hiding these dependencies within interface packages, the amount of code
  9297. modification can be reduced.
  9298.  
  9299. exceptions
  9300.  
  9301. It is often necessary to interact with other languages, if only an assembly 
  9302. language to reach certain hardware features. In these cases, clearly comment 
  9303. the requirements and limitations of the interface and pragma Interface usage. 
  9304.  
  9305. 7.6.5   Implementation-Defined Pragmas and Attributes
  9306.  
  9307. guideline
  9308.  
  9309. o       Avoid pragmas and attributes added by the compiler implementor.
  9310.  
  9311. rationale
  9312.  
  9313. The Ada Language Reference Manual (Department of Defense 1983) permits an 
  9314. implementor to add pragmas and attributes to exploit a particular hardware 
  9315. architecture or software environment. These are obviously even more 
  9316. implementation-specific and therefore less portable than an implementor's
  9317. interpretations of the predefined pragmas and attributes.
  9318.  
  9319. exceptions
  9320.  
  9321. Some implementation-dependent features are gaining wide acceptance in the Ada
  9322. community to help alleviate inherent inefficiencies in some Ada features. A
  9323. good example of this is the "fast interrupt" mechanism that provides a minimal
  9324. interrupt latency time in exchange for a restrictive tasking environment. Ada
  9325. community groups (e.g., SIGAda's ARTEWG) are attempting to standardize a
  9326. common mechanism and syntax to provide this capability. By being aware of
  9327. industry trends when specialized features must be used, you can take a more
  9328. general approach that will help minimize the porting job.
  9329.  
  9330. 7.6.6   Unchecked Deallocation
  9331.  
  9332. guideline
  9333.  
  9334. o       Avoid dependence on Unchecked_Deallocation (see Guideline ).
  9335.  
  9336. rationale
  9337.  
  9338. The unchecked storage deallocation mechanism is one method for overriding the
  9339. default time at which allocated storage is reclaimed. The earliest default
  9340. time is when an object is no longer accessible, e.g., when control leaves the
  9341. scope where an access type was declared (the exact point after this time is
  9342. implementation- dependent). Any unchecked deallocation of storage performed
  9343. prior to this may result in an erroneous Ada program if an attempt is made to
  9344. access the object.
  9345.  
  9346. This guideline is stronger than Guideline because of the extreme dependence on
  9347. the implementation of Unchecked_Deallocation. Using it could cause
  9348. considerable difficulty with portability.
  9349.  
  9350. exceptions
  9351.  
  9352. Using unchecked deallocation of storage can be beneficial in local control of 
  9353. highly iterative or recursive algorithms where available storage may be 
  9354. exceeded.
  9355.  
  9356. 7.6.7   Unchecked Conversion
  9357.  
  9358. guideline
  9359.  
  9360. o       Avoid using Unchecked_Conversion (see Guideline ).
  9361.  
  9362. rationale
  9363.  
  9364. The unchecked type conversion mechanism is, in effect, a means of bypassing
  9365. the strong typing facilities in Ada. An implementation is free to limit the
  9366. types that may be matched and the results that occur when object sizes differ.
  9367.  
  9368. exceptions
  9369.  
  9370. Unchecked type conversion is useful in implementation dependent parts of Ada 
  9371. programs (where lack of portability is isolated) where low-level programming
  9372. and foreign language interfacing is the objective. 
  9373.  
  9374. 7.6.8   Run Time Dependencies
  9375.  
  9376. guideline
  9377.  
  9378. o       Avoid the direct invocation of or implicit dependence upon an 
  9379. underlying host operating system or Ada run time support system.
  9380.  
  9381. rationale
  9382.  
  9383. Features of an implementation not specified in the Ada Language Reference 
  9384. Manual (Department of Defense 1983) will usually differ between 
  9385. implementations. Specific implementation-dependent features are not likely to
  9386. be provided in other implementations. Even if a majority of vendors eventually 
  9387. provide similar features, they are unlikely to have identical formulations. 
  9388. Indeed, different vendors may use the same formulation for (semantically) 
  9389. entirely different features.
  9390.  
  9391. Try to avoid these when coding. Consider the consequences of including system
  9392. calls in a program on a host development system. If these calls are not
  9393. flagged for removal and replacement, the program could go through development
  9394. and testing only to be unusable when moved to a target environment which lacks
  9395. the facilities provided by those system calls on the host.
  9396.  
  9397. exceptions
  9398.  
  9399. In real-time embedded systems, making calls to low-level support system
  9400. facilities may often be unavoidable. Isolate the uses of these facilities may
  9401. be too difficult. Comment them as you would machine code inserts (see
  9402. Guideline ); they are, in a sense, instructions for the virtual machine
  9403. provided by the support system. When isolating the uses of these features,
  9404. provide an interface for the rest of your program to use which can be ported
  9405. through replacement of the interface's implementation.
  9406.  
  9407. 7.7     INPUT/OUTPUT
  9408.  
  9409. Input/Output facilities in Ada are not a part of the syntactic definition of
  9410. the language. The constructs in the language have been used to define a set of
  9411. packages for this purpose. These packages are not expected to meet all the I/O
  9412. needs of all applications, in particular embedded systems. They serve as a
  9413. core subset that may be used on straightforward data, and that can be used as
  9414. examples of building I/O facilities upon the low-level constructs provided by
  9415. the language. Providing an I/O definition that could meet the requirements of
  9416. all applications and integrate with the many existing operating systems would
  9417. result in unacceptable implementation dependencies.
  9418.  
  9419. The types of portability problems encountered with I/O tend to be different
  9420. for applications running with a host operating system versus embedded targets
  9421. where the Ada run-time is self-sufficient. Interacting with a host operating
  9422. system offers the added complexity of coexisting with the host file system
  9423. structures (e.g., hierarchical directories), access methods (e.g., ISAM), and
  9424. naming conventions (e.g., logical names and aliases based on the current
  9425. directory).  The section on Input/Output in ARTEWG (1986) provides some
  9426. examples of this type of dependency. Embedded applications have different
  9427. dependencies that often tie them to the low-level details of their hardware
  9428. devices.
  9429.  
  9430. The major defense against these inherent implementation dependencies in I/O is
  9431. to try to isolate their functionality in any given application. The majority
  9432. of the following guidelines are focused in this direction.
  9433.  
  9434. 7.7.1   Name and Form Parameters
  9435.  
  9436. guideline
  9437.  
  9438. o       Use constants and variables as symbolic actuals for the Name and Form 
  9439. parameters on the predefined I/O packages. Declare and initialize them in an 
  9440. implementation dependency package. 
  9441.  
  9442. rationale
  9443.  
  9444. The format and allowable values of these parameters on the predefined I/O
  9445. packages can vary greatly between implementations. Isolation of these values
  9446. facilitates portability. Note that not specifying a Form string or using a
  9447. null value does not guarantee portability since the implementation is free to
  9448. specify defaults.
  9449.  
  9450. note
  9451.  
  9452. It may be desirable to further abstract the I/O facilities by defining 
  9453. additional Create and Open procedures that hide the visibility of the Form 
  9454. parameter entirely (see Pappas 1985, 54-55).
  9455.  
  9456. 7.7.2   File Closing
  9457.  
  9458. guideline
  9459.  
  9460. o       Close all files explicitly.
  9461.  
  9462. rationale
  9463.  
  9464. The Ada Language Reference Manual (Department of Defense 1983, w14.1) states,
  9465. "The language does not define what happens to external files after completion
  9466. of the main program (in particular, if corresponding files have not been
  9467. closed)." The possibilities range from being closed in an anticipated manner
  9468. to deletion.
  9469.  
  9470. The disposition of a closed temporary file may vary, perhaps affecting 
  9471. performance and space availability (ARTEWG 1986).
  9472.  
  9473. 7.7.3   I/O on Access Types
  9474.  
  9475. guideline
  9476.  
  9477. o       Avoid performing I/O on access types.
  9478.  
  9479. rationale
  9480.  
  9481. The Ada Language Reference Manual (Department of Defense 1983) does not require 
  9482. that it be supported. When such a value is written, it is placed out of reach 
  9483. of the implementation. Thus, it is out of reach of the reliability-enhancing
  9484. controls of strong type checking.
  9485.  
  9486. Consider the meaning of this operation. One possible implementation of the
  9487. values of access types is virtual addresses. If you write such a value, how
  9488. can you expect another program to read that value and make any sensible use of
  9489. it?  The value cannot be construed to refer to any meaningful location within
  9490. the reader's address space, nor can a reader infer any information about the
  9491. writer's address space from the value read. The latter is the same problem
  9492. that the writer would have trying to interpret or use the value if it is read
  9493. back in. To wit, a garbage collection and/or heap compaction scheme may have
  9494. moved the item formerly accessed by that value, leaving that value "pointing"
  9495. at space which is now being put to indeterminable uses by the underlying
  9496. implementation.
  9497.  
  9498. 7.7.4   Package Low_Level_IO
  9499.  
  9500. guideline
  9501.  
  9502. o       Minimize and isolate using the predefined package Low_Level_IO.
  9503.  
  9504. rationale
  9505.  
  9506. Low_Level_IO is intended to support direct interaction with physical devices
  9507. that are usually unique to a given host or target environment. In addition,
  9508. the data types provided to the procedures are implementation-defined. This
  9509. allows vendors to define different interfaces to an identical device.
  9510.  
  9511. exceptions
  9512.  
  9513. Those portions of an application that must deal with this level of I/O, e.g., 
  9514. device drivers and real-time components dealing with discretes, are inherently
  9515. nonportable. Where performance allows, structure these components to isolate 
  9516. the hardware interface. Only within these isolated portions is it advantageous 
  9517. to employ the Low_Level_IO interface which is portable in concept and general 
  9518. procedural interface, if not completely so in syntax and semantics.
  9519.  
  9520. 7.8     SUMMARY
  9521.  
  9522. fundamentals
  9523.  
  9524. o       Make considered assumptions about the support provided for the 
  9525. following on potential target platforms:
  9526.  
  9527. -       Number of bits available for type Integer (range constraints).
  9528.  
  9529. -       Number of decimal digits of precision available for floating point 
  9530. types.
  9531.  
  9532. -       Number of bits available for fixed-point types (delta and range
  9533. constraints).
  9534.  
  9535. -       Number of characters per line of source text.
  9536.  
  9537. -       Number of bits for Universal_Integer expressions.
  9538.  
  9539. -       Number of seconds for the range of Duration.
  9540.  
  9541. -       Number of milliseconds for Duration'Small. 
  9542.  
  9543. o       Don't implicitly use an implementation limit.
  9544.  
  9545. o       Use highlighting comments for each package, subprogram and task where 
  9546. any nonportable features are present. 
  9547.  
  9548. o       For each nonportable feature employed, describe the expectations for 
  9549. that feature.
  9550.  
  9551. o       Use only a parameterless procedure as the main program.
  9552.  
  9553. o       Create packages specifically designed to isolate hardware and 
  9554. implementation dependencies and designed so that their specification will not 
  9555. change.
  9556.  
  9557. o       Clearly indicate the objectives if machine or solution efficiency is 
  9558. the reason for hardware or implementation dependent code.
  9559.  
  9560. o       For the packages that hide implementation dependencies, maintain 
  9561. different package bodies for different target environments.
  9562.  
  9563. o       Isolate interrupt receiving tasks into implementation dependent 
  9564. packages.
  9565.  
  9566. o       Avoid the use of vendor supplied packages.
  9567.  
  9568. o    Avoid the use of features added to the predefined packages that are
  9569. not specified in the language definition.
  9570.  
  9571. numeric types and expressions
  9572.  
  9573. o    Do not use the predefined numeric types in package Standard. Use
  9574. range and digits declarations and let the implementation do the derivation
  9575. implicitly from the predefined types.
  9576.  
  9577. o       For programs that require greater accuracy than that provided by the 
  9578. global assumptions, define a package that declares a private type and 
  9579. operations as needed; see Pappas (1985) for a full explanation and examples.
  9580.  
  9581. o       Know the Ada model for floating point types and arithmetic.
  9582.  
  9583. o       Carefully analyze what accuracy and precision you really need.
  9584.  
  9585. o       Do not press the accuracy limits of the machine(s).
  9586.  
  9587. o       Comment the analysis and derivation of the numerical aspects of a 
  9588. program.
  9589.  
  9590. o       Use named numbers or universal real expressions rather than constants 
  9591. of any particular type.
  9592.  
  9593. o       Anticipate values of subexpressions to avoid exceeding the range of 
  9594. their type. Use derived types, subtypes, factoring, and range constraints on 
  9595. numeric types as described in Guidelines , , and .
  9596.  
  9597. o    Use <= and >= to do relational tests on real valued arguments,
  9598. avoiding the <, >, =, and /= operations.
  9599.  
  9600. o       Use values of type attributes in comparisons and checking for small 
  9601. values.
  9602.  
  9603. storage control
  9604.  
  9605. o        Do not use a representation clause to specify number of storage units.
  9606.  
  9607. tasking
  9608.  
  9609. o       Do not depend on the order in which task objects are activated when 
  9610. declared in the same declarative list.
  9611.  
  9612. o    Do not depend on a particular delay being achievable (Nissen and
  9613. Wallis 1984).
  9614.  
  9615. o       Never use a busy waiting loop instead of a delay.
  9616.  
  9617. o       Design to limit polling to those cases where it is absolutely 
  9618. necessary.
  9619.  
  9620. o    Never use knowledge of the execution pattern of tasks to achieve
  9621. timing requirements.
  9622.  
  9623. o    Do not assume a correlation between System.Tick and package Calendar
  9624. or type Duration (see Guideline ).
  9625.  
  9626. o       Do not depend on the order in which guard conditions are evaluated or 
  9627. on the algorithm for choosing among several open select alternatives.
  9628.  
  9629. o       Do not assume that tasks execute uninterrupted until they reach a 
  9630. synchronization point.
  9631.  
  9632. o       Use pragma Priority to distinguish general levels of importance only 
  9633. (see Guideline ).
  9634.  
  9635. o       Avoid using the abort statement.
  9636.  
  9637. o       Do not share variables. 
  9638.  
  9639. o       Have tasks communicate through the rendezvous mechanism.
  9640.  
  9641. o       Do not use shared variables as a task synchronization device.
  9642.  
  9643. o       Use pragma Shared only when you are forced to by run time system 
  9644. deficiencies.
  9645.  
  9646. exceptions
  9647.  
  9648. o     Do not depend on the exact locations at which predefined exceptions
  9649. are raised.
  9650.  
  9651. o       Catch Numeric_Error exceptions with a Numeric_Error | Constraint_Error 
  9652. exception handler.
  9653.  
  9654. o       Do not use a separate exception handler for Numeric_Error and 
  9655. Constraint_Error.
  9656.  
  9657. o       Do not raise implementation-defined exceptions.
  9658.  
  9659. o       Convert implementation defined exceptions within interface packages to 
  9660. visible user-defined exceptions.
  9661.  
  9662. representation clauses and implementation-dependent features
  9663.  
  9664. o    Use algorithms that do not depend on the representation of the data
  9665. and therefore do not need representation clauses.
  9666.  
  9667. o       Use representation clauses when accessing interface data or when a 
  9668. specific representation is needed to implement a design.
  9669.  
  9670. o    Avoid using package System constants except in attempting to
  9671. generalize other machine dependent constructs.
  9672.  
  9673. o       Avoid machine code inserts.
  9674.  
  9675. o       Avoid interfacing Ada with other languages. 
  9676.  
  9677. o       Isolate all subprograms employing pragma Interface to 
  9678. implementation-dependent (interface) package bodies.
  9679.  
  9680. o       Avoid pragmas and attributes added by the compiler implementor.
  9681.  
  9682. o       Avoid dependence on Unchecked_Deallocation (see Guideline ).
  9683.  
  9684. o       Avoid using Unchecked_Conversion (see Guideline ).
  9685.  
  9686. o       Avoid the direct invocation of or implicit dependence upon an 
  9687. underlying host operating system or Ada run time support system.
  9688.  
  9689. input/output
  9690.  
  9691. o       Use constants and variables as symbolic actuals for the Name and Form 
  9692. parameters on the predefined I/O packages. Declare and initialize them in an 
  9693. implementation dependency package. 
  9694.  
  9695. o       Close all files explicitly.
  9696.  
  9697. o       Avoid performing I/O on access types.
  9698.  
  9699. o       Minimize and isolate using the predefined package Low_Level_IO.
  9700.  
  9701.  
  9702.  
  9703.  
  9704. CHAPTER 8
  9705. Reusability
  9706.  
  9707. Reusability is the extent to which code can be used in different applications
  9708. with minimal change. As code is reused in a new application, that new
  9709. application partially inherits the attributes of that code. If it is
  9710. maintainable, the application is more maintainable. If it is portable, then
  9711. the application is more portable. So this chapter's guidelines are most useful
  9712. when all of the other guidelines in this book are also applied.
  9713.  
  9714. Several guidelines are directed at the issue of maintainability. Maintainable
  9715. code is easy to change to meet new or changing requirements. Maintainability
  9716. plays a special role in reuse. When attempts are made to reuse code, it is
  9717. often necessary to change it to suit the new application. If the code cannot
  9718. be changed easily, it is less likely to be reused.
  9719.  
  9720. There are many issues involved in software reuse: whether to reuse parts, how
  9721. to store and retrieve reusable parts in a library, how to certify parts, how
  9722. to maximize the economic value of reuse, how to provide incentives to
  9723. engineers and entire companies to reuse parts rather than reinvent them, and
  9724. so on. This chapter ignores these managerial, economic, and logistic issues to
  9725. focus on the single technical issue of how to write software parts in Ada to
  9726. increase reuse potential. The other issues are just as important but are
  9727. outside of the scope of this book.
  9728.  
  9729. One of the design goals of Ada was to facilitate the creation and use of
  9730. reusable parts to improve productivity. To this end, Ada provides features to
  9731. develop reusable parts and to adapt them once they are available. Packages,
  9732. visibility control, and separate compilation support modularity and
  9733. information hiding (see Guidelines , , , and ). This allows the separation of
  9734. application-specific parts of the code, maximizes the general purpose parts
  9735. suitable for reuse, and allows the isolation of design decisions within
  9736. modules, facilitating change. The Ada type system supports localization of
  9737. data definitions so that consistent changes are easy to make. Generic units
  9738. directly support the development of general purpose, adaptable code that can
  9739. be instantiated to perform specific functions. Using these features carefully,
  9740. and in conformance to the guidelines in this book, produces code that is more
  9741. likely to be reusable.
  9742.  
  9743. Reusable code is developed in many ways. Code may be scavenged from a previous 
  9744. project. A reusable library of code may be developed from scratch for a 
  9745. particularly well understood domain: such as a math library. Reusable code may 
  9746. be developed as an intentional byproduct of a specific application. Reusable 
  9747. code may be developed a certain way because a design method requires it. These 
  9748. guidelines are intended to apply in all of these situations.
  9749.  
  9750. The experienced programmer recognizes that software reuse is much more a 
  9751. requirements and design issue than a coding issue. The guidelines in this 
  9752. section are intended to work within an overall method for developing reusable 
  9753. code. This section will not deal with artifacts of design, testing, etc. Some 
  9754. research into reuse issues related specifically to the Ada language can be 
  9755. found in AIRMICS (1990), Edwards (1990), and Wheeler (1992).
  9756.  
  9757. Regardless of development method, experience indicates that reusable code has 
  9758. certain characteristics, and this chapter makes the following assumptions:
  9759.  
  9760. -       Reusable parts must be understandable. A reusable part should be a 
  9761. model of clarity. The requirements for commenting reusable parts are even more 
  9762. stringent than those for parts specific to a particular application. 
  9763.  
  9764. -    Reusable parts must be of the highest possible quality. They must be
  9765. correct, reliable, and robust. An error or weakness in a reusable part may
  9766. have far-reaching consequences, and it is important that other programmers can
  9767. have a high degree of confidence in any parts offered for reuse.
  9768.  
  9769. -       Reusable parts must be adaptable. To maximize its reuse potential, a 
  9770. part must be able to adapt to the needs of a wide variety of users.
  9771.  
  9772. -       Reusable parts should be independent. It should be possible to reuse a 
  9773. single part without also adopting many other parts that are apparently 
  9774. unrelated.
  9775.  
  9776. In addition to these criteria, a reusable part must be easier to reuse than to 
  9777. reinvent, must be efficient, and must be portable. If it takes more effort to 
  9778. reuse a part than to create one from scratch, or if the reused part is simply 
  9779. not efficient enough, reuse does not occur as readily. For guidelines on 
  9780. portability, see Chapter 7.
  9781.  
  9782. This chapter should not be read in isolation. In many respects, a
  9783. well-written, reusable component is simply an extreme example of a
  9784. well-written component.  All of the guidelines in the previous chapters apply
  9785. to reusable components as well as components specific to a single application.
  9786. The guidelines listed here apply specifically to reusable components.
  9787.  
  9788. 8.1     UNDERSTANDING AND CLARITY
  9789.  
  9790. It is particularly important that parts intended for reuse should be easy to
  9791. understand. The following must be immediately apparent from inspection of the
  9792. comments and the code itself: what the part does, how to use it, what
  9793. anticipated changes might be made to it in the future, and how it works. For
  9794. maximum readability of reusable parts, follow the guidelines in Chapter 3,
  9795. some of which are repeated more strongly below.
  9796.  
  9797. 8.1.1   Application-Independent Naming
  9798.  
  9799. guideline
  9800.  
  9801. o       Select the least restrictive names possible for reusable parts and 
  9802. their identifiers.
  9803.  
  9804. o       Select the generic name to avoid conflicting with the naming 
  9805. conventions of instantiations of the generic.
  9806.  
  9807. o    Use names which indicate the behavioral characteristics of the
  9808. reusable part, as well as its abstraction.
  9809.  
  9810. example
  9811.  
  9812. General-purpose stack abstraction:
  9813.  
  9814. ------------------------------------------------------------------------
  9815. generic
  9816.  
  9817.    type Item is limited private;
  9818.    ...
  9819.  
  9820. package Bounded_Stack is
  9821.  
  9822.    procedure Push (New_Item    : in     Item);
  9823.    procedure Pop  (Newest_Item : in     Item);
  9824.    ...
  9825.  
  9826. end Bounded_Stack;
  9827. ------------------------------------------------------------------------
  9828.  
  9829. Renamed appropriately for use in current application:
  9830.  
  9831. ------------------------------------------------------------------------
  9832. with Bounded_Stack;
  9833. package Cafeteria is
  9834.  
  9835.    type Tray is limited private;
  9836.  
  9837.    package Tray_Stack is new Bounded_Stack (Item => Tray , ...);
  9838.  
  9839.    ...
  9840. end Cafeteria;
  9841. ------------------------------------------------------------------------
  9842.  
  9843. rationale
  9844.  
  9845. Choosing a general or application-independent name for a reusable part
  9846. encourages its wide reuse. When the part is used in a specific context, it can 
  9847. be instantiated (if generic) or renamed with a more specific name.
  9848.  
  9849. When there is an obvious choice for the simplest, clearest name for a reusable 
  9850. part, it is a good idea to leave that name for use by the reuser of the part, 
  9851. choosing a longer, more descriptive name for the reusable part. Thus, 
  9852. Bounded_Stack is a better name than Stack for a generic stack package because 
  9853. it leaves the simpler name Stack available to be used by an instantiation.
  9854.  
  9855. Include indications of the behavioral characteristics (but not indications of 
  9856. the implementation) in the name of a reusable part so that multiple parts with 
  9857. the same abstraction (e.g., multiple stack packages) but with different 
  9858. restrictions (bounded, unbounded, etc.) can be stored in the same Ada library 
  9859. and used as part of the same Ada program.
  9860.  
  9861. 8.1.2   Abbreviations
  9862.  
  9863. guideline
  9864.  
  9865. o       Do not use any abbreviations in identifier or unit names.
  9866.  
  9867. example
  9868.  
  9869. ------------------------------------------------------------------------
  9870. with Calendar;
  9871. package Greenwich_Mean_Time is
  9872.  
  9873.    function Clock return Calendar.Time;
  9874.    ...
  9875.  
  9876. end Greenwich_Mean_Time;
  9877. ------------------------------------------------------------------------
  9878.  
  9879. But the following abbreviation may not be clear when used in an application.
  9880.  
  9881. with Calendar;
  9882. with Greenwich_Mean_Time;
  9883. ...
  9884.  
  9885.    function Get_GMT return Calendar.Time renames
  9886.       Greenwich_Mean_Time.Clock;
  9887.  
  9888. rationale
  9889.  
  9890. This is a stronger guideline than Guideline . However well commented, an
  9891. abbreviation may cause confusion in some future reuse context. Even
  9892. universally accepted abbreviations, such as GMT for Greenwich Mean Time, can
  9893. cause problems and should be used only with great caution.
  9894.  
  9895. The difference between this guideline and Guideline 3.1.4 involves issues of
  9896. domain.  When the domain is well-defined, abbreviations and acronyms that are
  9897. accepted in that domain will clarify the meaning of the application.  When
  9898. that same code is removed from its domain-specific context, those
  9899. abbreviations may become meaningless.
  9900.  
  9901. In the example above, the package, Greenwich_Mean_Time, could be used in any 
  9902. application without loss of meaning.  But the function Get_GMT could easily be 
  9903. confused with some other acronym in a different domain.
  9904.  
  9905. note
  9906.  
  9907. See Guideline 5.7.2 concerning the proper use of the renames clause.  If a 
  9908. particular application makes extensive use of the Greenwich_Mean_Time domain, 
  9909. it may be appropriate to rename the package, GMT, within that application:
  9910.  
  9911. with Greenwich_Mean_Time;
  9912. ...
  9913.  
  9914.    package GMT renames Greenwich_Mean_Time;
  9915.  
  9916. 8.1.3   Generic Formal Parameters
  9917.  
  9918. guideline
  9919.  
  9920. o    Document the expected behavior of generic formal parameters just as
  9921. any package specification is documented.
  9922.  
  9923. example
  9924.  
  9925. The following example shows how a very general algorithm can be developed, but 
  9926. must be clearly documented to be used:
  9927.  
  9928. ------------------------------------------------------------------------
  9929. generic
  9930.  
  9931.    -- Index provides access to values in a structure.  For example,
  9932.    -- an array, A.
  9933.    type Index is (<>);
  9934.  
  9935.    -- The function, Less_Than, does NOT compare the indexes
  9936.    -- themselves;it compares the elements of the structure:
  9937.    --     Less_Than (i,j)  <==>  A(i) < A(j)
  9938.    with function Less_Than (Index1 : in     Index;
  9939.                 Index2 : in     Index)
  9940.      return Boolean;
  9941.  
  9942.    -- This procedure swaps values of the structure (the mode won't
  9943.    -- allow the indexes themselves to be swapped!):
  9944.    --     Less_Than (i,j) and then Swap (i,j)  ==>  Less_Than (j,i).
  9945.    with procedure Swap (Index1 : in     Index;
  9946.             Index2 : in     Index);
  9947.  
  9948.    -- After the call to Quick_Sort, the indexed structure will be
  9949.    -- sorted:
  9950.    --     For all i,j in First..Last :  i<j  =>  A(i) < A(j).
  9951.  
  9952. procedure Quick_Sort (First : in     Index := Index'First;
  9953.               Last  : in     Index := Index'Last);
  9954. ------------------------------------------------------------------------
  9955.  
  9956. rationale
  9957.  
  9958. The generic capability is one of Ada's strongest features because of its 
  9959. formalization.  However, not all of the assumptions made about generic formal 
  9960. parameters can be expressed directly in Ada.  It is important that any user of 
  9961. a generic know exactly what that generic needs in order to behave correctly.
  9962.  
  9963. In a sense, a generic specification is a contract where the instantiator must 
  9964. supply the formal parameters and in return receives a working instance of the 
  9965. specification.  Both parties are best served when the contract is complete and 
  9966. clear about all assumptions.
  9967.  
  9968. 8.2     ROBUSTNESS
  9969.  
  9970. The following guidelines improve the robustness of Ada code. It is easy to
  9971. write code that depends on an assumption which you do not realize that you are
  9972. making. When such a part is reused in a different environment, it can break
  9973. unexpectedly. The guidelines below show some ways in which Ada code can be
  9974. made to automatically conform to its environment, and some ways in which it
  9975. can be made to check for violations of assumptions. Finally, some guidelines
  9976. are given to warn you about errors which Ada does not catch as soon as you
  9977. might like.
  9978.  
  9979. 8.2.1   Named Numbers
  9980.  
  9981. guideline
  9982.  
  9983. o    Use named numbers and static expressions to allow multiple
  9984. dependencies to be linked to a small number of symbols.
  9985.  
  9986. example
  9987.  
  9988. ------------------------------------------------------------------------
  9989. procedure Disk_Driver is
  9990.  
  9991.    -- In this procedure, a number of important disk parameters are
  9992.    -- linked.
  9993.    Number_Of_Sectors  : constant :=     4;
  9994.    Number_Of_Tracks   : constant :=   200;
  9995.    Number_Of_Surfaces : constant :=    18;
  9996.    Sector_Capacity    : constant := 4_096;
  9997.  
  9998.    Track_Capacity   : constant := Number_Of_Sectors  * Sector_Capacity;
  9999.    Surface_Capacity : constant := Number_Of_Tracks   * Track_Capacity;
  10000.    Disk_Capacity    : constant := Number_Of_Surfaces * Surface_Capacity;
  10001.  
  10002.    type Sector_Range  is range 1 .. Number_Of_Sectors;
  10003.    type Track_Range   is range 1 .. Number_Of_Tracks;
  10004.    type Surface_Range is range 1 .. Number_Of_Surfaces;
  10005.  
  10006.    type Track_Map   is array (Sector_Range)  of ...;
  10007.    type Surface_Map is array (Track_Range)   of Track_Map;
  10008.    type Disk_Map    is array (Surface_Range) of Surface_Map;
  10009.  
  10010. begin  -- Disk_Driver
  10011.    ...
  10012. end Disk_Driver;
  10013. ------------------------------------------------------------------------
  10014.  
  10015. rationale
  10016.  
  10017. To reuse software that uses named numbers and static expressions
  10018. appropriately, just one or a small number of constants need to be reset and
  10019. all declarations and associated code are changed automatically. Apart from
  10020. easing reuse, this reduces the number of opportunities for error and documents
  10021. the meanings of the types and constants without using error-prone comments.
  10022.  
  10023. 8.2.2   Unconstrained Arrays
  10024.  
  10025. guideline
  10026.  
  10027. o       Use unconstrained array types for array formal parameters and array 
  10028. return values.
  10029.  
  10030. o       Make the size of local variables depend on actual parameter size where 
  10031. appropriate.
  10032.  
  10033. example
  10034.  
  10035.    ...
  10036.    type Vector is array (Vector_Index range <>) of Element;
  10037.    type Matrix is array
  10038.      (Vector_Index range <>, Vector_Index range <>) of Element;
  10039.    ...
  10040.  
  10041.    ---------------------------------------------------------------------
  10042.    procedure Matrix_Operation (Data : in     Matrix) is
  10043.  
  10044.       Workspace   : Matrix (Data'Range(1), Data'Range(2));
  10045.       Temp_Vector : Vector (Data'First(1) .. 2 * Data'Last(1));
  10046.    ...
  10047.    ---------------------------------------------------------------------
  10048.  
  10049. rationale
  10050.  
  10051. Unconstrained arrays can be declared with their sizes dependent on formal
  10052. parameter sizes. When used as local variables, their sizes change
  10053. automatically with the supplied actual parameters. This facility can be used
  10054. to assist in the adaption of a part since necessary size changes in local
  10055. variables are taken care of automatically.
  10056.  
  10057. 8.2.3   Assumptions
  10058.  
  10059. guideline
  10060.  
  10061. o       Minimize the number of assumptions made by a unit.
  10062.  
  10063. o       For assumptions which cannot be avoided, use types to automatically 
  10064. enforce conformance.
  10065.  
  10066. o       For assumptions which cannot be automatically enforced by types, add 
  10067. explicit checks to the code.
  10068.  
  10069. o       Document all assumptions.
  10070.  
  10071. example
  10072.  
  10073. The following poorly written function documents, but does not check, its 
  10074. assumption:
  10075.  
  10076.    -- Assumption:  BCD value is less than 4 digits.
  10077.    function Binary_To_BCD (Binary_Value : in     Natural)
  10078.      return BCD;
  10079.  
  10080. The next example enforces conformance with its assumption, making the checking 
  10081. automatic, and the comment unnecessary:
  10082.  
  10083.    type Binary_Values is new Natural range 0 .. 9_999;
  10084.  
  10085.    function Binary_To_BCD (Binary_Value : in     Binary_Values)
  10086.      return BCD;
  10087.  
  10088. The next example explicitly checks and documents its assumption:
  10089.  
  10090.    ---------------------------------------------------------------------
  10091.    -- Out_Of_Range raised when BCD value exceeds 4  digits.
  10092.    function Binary_To_BCD (Binary_Value : in     Natural)
  10093.      return BCD is
  10094.  
  10095.       Maximum_Representable : constant Natural := 9_999;
  10096.  
  10097.    begin  -- Binary_To_BCD
  10098.       if Binary_Value > Maximum_Representable then
  10099.      raise Out_Of_Range;
  10100.       end if;
  10101.  
  10102.       ...
  10103.    end Binary_To_BCD;
  10104.    ---------------------------------------------------------------------
  10105.  
  10106. rationale
  10107.  
  10108. Any part that is intended to be used again in another program, especially if
  10109. the other program is likely to be written by other people, should be robust.
  10110. It should defend itself against misuse by defining its interface to enforce as
  10111. many assumptions as possible and by adding explicit defensive checks on
  10112. anything which cannot be enforced by the interface.
  10113.  
  10114. note
  10115.  
  10116. You can restrict the ranges of values of the inputs by careful selection or 
  10117. construction of the types of the formal parameters. When you do so, the 
  10118. compiler-generated checking code may be more efficient than any checks you
  10119. might write. Indeed, such checking is part of the intent of the strong typing 
  10120. in the language. This presents a challenge, however, for generic units where 
  10121. the user of your code selects the types of the parameters. Your code must be 
  10122. constructed so as to deal with any value of any type the user may choose to 
  10123. select for an instantiation.
  10124.  
  10125. 8.2.4   Subtypes in Generic Specifications
  10126.  
  10127. guideline
  10128.  
  10129. o       Beware of using subtypes as type marks when declaring generic formal 
  10130. objects of type in out.
  10131.  
  10132. o       Beware of using subtypes as type marks when declaring parameters or 
  10133. return values of generic formal subprograms.
  10134.  
  10135. o       Use attributes rather than literal values.
  10136.  
  10137. example
  10138.  
  10139. In the following example, it appears that any value supplied for the generic 
  10140. formal object Object would be constrained to the range 1..10. It also appears 
  10141. that parameters passed at run-time to the Put routine in any instantiation, and
  10142. values returned by the Get routine, would be similarly constrained. 
  10143.  
  10144.    subtype Range_1_10 is Integer range 1 .. 10;
  10145.  
  10146.    ---------------------------------------------------------------------
  10147.    generic
  10148.  
  10149.       Object : in out Range_1_10;
  10150.       with procedure Put (Parameter : in     Range_1_10);
  10151.       with function  Get  return             Range_1_10;
  10152.  
  10153.    package Input_Output is
  10154.       ...
  10155.    end Input_Output;
  10156.    ---------------------------------------------------------------------
  10157.  
  10158. However, this is not the case. Given the following legal instantiation:
  10159.  
  10160.    subtype Range_15_30 is Integer range 15 .. 30;
  10161.    Constrained_Object : Range_15_30 := 15;
  10162.  
  10163.    procedure Constrained_Put (Parameter : in     Range_15_30);
  10164.    function  Constrained_Get  return             Range_15_30;
  10165.  
  10166.    package Constrained_Input_Output
  10167.       is new Input_Output (Object => Constrained_Object,
  10168.                Put    => Constrained_Put,
  10169.                Get    => Constrained_Get);
  10170.  
  10171.    ...
  10172.  
  10173. Object, Parameter, and the return value of Get are constrained to the range 
  10174. 15..30. Thus, for example, if the body of the generic package contains an 
  10175. assignment statement:
  10176.  
  10177. Object := 1;
  10178.  
  10179. Constraint_Error is raised when this instantiation is executed. 
  10180.  
  10181. rationale
  10182.  
  10183. According to Sections 12.1.1(5) and 12.1.3(5) of the Ada Language Reference 
  10184. Manual (Department of Defense 1983), when constraint checking is performed for 
  10185. generic formal objects, and parameters and return values of generic formal 
  10186. subprograms, the constraints of the actual subtype (not the formal subtype or 
  10187. the base type) are enforced. 
  10188.  
  10189. Thus, even with a generic unit which has been instantiated and tested many
  10190. times, and with an instantiation which reported no errors at instantiation
  10191. time, there can be a run-time error. Since the subtype constraints of the
  10192. generic formal are ignored, the Ada Language Reference Manual (Department of
  10193. Defense 1983) suggests using the name of a base type in such places to avoid
  10194. confusion. Even so, you must be careful not to assume the freedom to use any
  10195. value of the base type because the instantiation imposes the subtype
  10196. constraints of the generic actual parameter. To be safe, always refer to
  10197. specific values of the type via symbolic expressions containing attributes
  10198. like 'First, 'Last, 'Pred, and 'Succ rather than via literal values.
  10199.  
  10200. The best solution is to introduce a new generic formal type parameter and use 
  10201. it in place of the subtype, as shown below:
  10202.  
  10203. ------------------------------------------------------------------------
  10204. generic
  10205.    type Object_Range is range <>;
  10206.    Object : in out Object_Range;
  10207.  
  10208.    with procedure Put (Parameter : in     Object_Range);
  10209.    with function  Get  return             Object_Range;
  10210.  
  10211. package Input_Output is
  10212.    ...
  10213. end Input_Output;
  10214. ------------------------------------------------------------------------
  10215.  
  10216. This is a clear statement by the developer of the generic unit that no 
  10217. assumptions are made about the Objects type other than that it is an integer 
  10218. type. This should reduce the likelihood of any invalid assumptions being made 
  10219. in the body of the generic unit.
  10220.  
  10221. For generics, attributes provide the means to maintain generality.  It is 
  10222. possible to use literal values, but literals run the risk of violating some 
  10223. constraint.  For example, assuming an array's index starts at one may cause a 
  10224. problem when the generic is instantiated for a zero-based array type.
  10225.  
  10226. 8.2.5   Overloading in Generic Units
  10227.  
  10228. guideline
  10229.  
  10230. o       Be careful about overloading the names of subprograms exported by the 
  10231. same generic package.
  10232.  
  10233. example
  10234.  
  10235. ------------------------------------------------------------------------
  10236. generic
  10237.    type Item is limited private;
  10238.  
  10239. package Input_Output is
  10240.  
  10241.    procedure Put (Value : in     Integer);
  10242.    procedure Put (Value : in     Items);
  10243.  
  10244. end Input_Output;
  10245. ------------------------------------------------------------------------
  10246.  
  10247. rationale
  10248.  
  10249. If the generic package shown in the example above is instantiated with Integer
  10250. (or any subtype of Integer) as the actual type corresponding to generic formal
  10251. Value, then the two Put procedures have identical interfaces, and all calls to
  10252. Put are ambiguous. Therefore, this package cannot be used with type Integer.
  10253. In such a case, it is better to give unambiguous names to all subprograms. See
  10254. Section 12.3(22) of the Ada Language Reference Manual (Department of Defense
  10255. 1983) for more information.
  10256.  
  10257. 8.2.6   Hidden Tasks
  10258.  
  10259. guideline
  10260.  
  10261. o       Within a specification, document any tasks that would be activated by 
  10262. with'ing the specification and by using any part of the specification.
  10263.  
  10264. o       Document which generic formal parameters are accessed from a task 
  10265. hidden inside the generic unit.
  10266.  
  10267. rationale
  10268.  
  10269. The effects of tasking becomes a major factor when reusable code enters the
  10270. domain of real-time systems.  Even though tasks may be used for other
  10271. purposes, their effect on scheduling algorithms is still a concern and must be
  10272. clearly documented.  With the task clearly documented, the real-time
  10273. programmer can then analyze performance, priorities, and so forth to meet
  10274. timing requirements; or if necessary, he can modify or even redesign the
  10275. component.
  10276.  
  10277. Concurrent access to data structures must be carefully planned to avoid
  10278. errors, especially for data structures which are not atomic (see Chapter 6 for
  10279. details). If a generic unit accesses one of its generic formal parameters
  10280. (reads or writes the value of a generic formal object or calls a generic
  10281. formal subprogram which reads or writes data) from within a task contained in
  10282. the generic unit, then there is the possibility of concurrent access for which
  10283. the user may not have planned. In such a case, the user should be warned by a
  10284. comment in the generic specification.
  10285.  
  10286. 8.2.7   Exceptions
  10287.  
  10288. guideline
  10289.  
  10290. o       Propagate exceptions out of reusable parts. Handle exceptions within 
  10291. reusable parts only when you are certain that the handling is appropriate in 
  10292. all circumstances.
  10293.  
  10294. o    Propagate exceptions raised by generic formal subprograms after
  10295. performing any cleanup necessary to the correct operation of future
  10296. invocations of the generic instantiation.
  10297.  
  10298. o       Leave state variables in a valid state when raising an exception.
  10299.  
  10300. o       Leave parameters unmodified when raising an exception.
  10301.  
  10302. example
  10303.  
  10304. ------------------------------------------------------------------------
  10305. generic
  10306.  
  10307.    type Number is limited private;
  10308.  
  10309.    with procedure Get (Value :    out Number);
  10310.  
  10311. procedure Process_Numbers;
  10312.  
  10313.  
  10314. ------------------------------------------------------------------------
  10315. procedure Process_Numbers is
  10316.  
  10317.    Local : Number;
  10318.  
  10319.    procedure Perform_Cleanup_Necessary_For_Process_Numbers is
  10320.      separate;
  10321.    ...
  10322.  
  10323. begin  -- Process_Numbers
  10324.    ...
  10325.  
  10326.    Catch_Exceptions_Generated_By_Get:
  10327.       begin
  10328.      Get(Local);
  10329.  
  10330.       exception
  10331.      when others =>
  10332.         Perform_Cleanup_Necessary_For_Process_Numbers;
  10333.         raise;
  10334.       end Catch_Exceptions_Generated_By_Get;
  10335.  
  10336.    ...
  10337. end Process_Numbers;
  10338. ------------------------------------------------------------------------
  10339.  
  10340. rationale
  10341.  
  10342. On most occasions, an exception is raised because an undesired event (such as 
  10343. floating-point overflow) has occurred. Such events often need to be dealt with
  10344. entirely differently with different uses of a particular software part. It is 
  10345. very difficult to anticipate all the ways that users of the part may wish to 
  10346. have the exceptions handled. Passing the exception out of the part is the 
  10347. safest treatment.
  10348.  
  10349. In particular, when an exception is raised by a generic formal subprogram, the
  10350. generic unit is in no position to understand why or to know what corrective
  10351. action to take. Therefore, such exceptions should always be propagated back to
  10352. the caller of the generic instantiation. However, the generic unit must first
  10353. clean up after itself, restoring its internal data structures to a correct
  10354. state so that future calls may be made to it after the caller has dealt with
  10355. the current exception. For this reason, all calls to generic formal
  10356. subprograms should be within the scope of a when others exception handler if
  10357. the internal state is modified, as shown in the example above.
  10358.  
  10359. When a reusable part is invoked, the user of the part should be able to know
  10360. exactly what operation (at the appropriate level of abstraction) has been
  10361. performed. For this to be possible, a reusable part must always do all or none
  10362. of its specified function; it must never do half. Therefore, any reusable part
  10363. which terminates early by raising or propagating an exception should return to
  10364. the caller with no effect on the internal or external state. The easiest way
  10365. to do this is to test for all possible exceptional conditions before making
  10366. any state changes (modifying internal state variables, making calls to other
  10367. reusable parts to modify their states, updating files, etc.). When this is not
  10368. possible, it is best to restore all internal and external states to the values
  10369. which were current when the part was invoked before raising or propagating the
  10370. exception. Even when this is not possible, it is important to document this
  10371. potentially hazardous situation in the comment header of the specification of
  10372. the part.
  10373.  
  10374. A similar problem arises with parameters of mode out or in out when exceptions 
  10375. are raised. The Ada language defines these modes in terms of "copy-in" and
  10376. "copy-back" semantics, but leaves the actual parameter-passing mechanism
  10377. undefined. When an exception is raised, the copy-back does not occur, but for
  10378. an Ada compiler which passes parameters by reference, the actual parameter has 
  10379. already been updated. When parameters are passed by copy, the update does not 
  10380. occur. To reduce ambiguity, increase portability, and avoid situations where 
  10381. some but not all of the actual parameters are updated when an exception is 
  10382. raised, it is best to treat values of out and in out parameters like state 
  10383. variables, updating them only after it is certain that no exception will be 
  10384. raised.
  10385.  
  10386. 8.3     ADAPTABILITY
  10387.  
  10388. Reusable parts often need to be changed before they can be used in a specific 
  10389. application. They should be structured so that change is easy and as localized 
  10390. as possible. One way of achieving adaptability is to create general parts with 
  10391. complete functionality, only a subset of which might be needed in a given 
  10392. application. Another is to use Ada's generic construct to produce parts that 
  10393. can be appropriately instantiated with different parameters. Both of these 
  10394. approaches avoid the error-prone process of adapting a part by changing its
  10395. code, but have limitations and can carry some overhead.
  10396.  
  10397. Anticipated changes, that is, changes that can be reasonably foreseen by the
  10398. developer of the part, should be provided for as far as possible.
  10399. Unanticipated change can only be accommodated by carefully structuring a part
  10400. to be adaptable. Many of the considerations pertaining to maintainability
  10401. apply. If the code is of high quality, clear, and conforms to well-established
  10402. design principles such as information hiding, it is easier to adapt in
  10403. unforeseen ways.
  10404.  
  10405. 8.3.1   Complete Functionality
  10406.  
  10407. guideline
  10408.  
  10409. o       Provide complete functionality in a reusable part or set of parts. 
  10410. Build in complete functionality, including end conditions, even if some 
  10411. functionality is not needed in this application.
  10412.  
  10413. o       More specifically, provide initialization and finalization procedures 
  10414. for every data structure that may contain dynamic data.
  10415.  
  10416. example
  10417.  
  10418.    Incoming : Queue;
  10419.    ...
  10420.  
  10421.    Initialize(Incoming);      -- initialization operation
  10422.    ...
  10423.  
  10424.    if Is_Full(Incoming) then  -- query operation
  10425.       ...
  10426.    end if;
  10427.  
  10428.    ...
  10429.  
  10430.    Finalize(Incoming);        -- finalization operation
  10431.  
  10432. rationale
  10433.  
  10434. This is particularly important in designing/programming an abstraction. 
  10435. Completeness ensures that you have configured the abstraction correctly, 
  10436. without built-in assumptions about its execution environment. It also ensures
  10437. the proper separation of functions so that they are useful to the current 
  10438. application and, in other combinations, to other applications. It is 
  10439. particularly important that they be available to other applications; remember 
  10440. that they can be "optimized" out of the final version of the current product.
  10441.  
  10442. When a reusable part can reasonably be implemented using dynamic data, then
  10443. any application that must control memory can use the initialization and
  10444. finalization routines to guard against memory leakage.  Then if data
  10445. structures become dynamic, the applications that are sensitive to these
  10446. concerns can be easily adapted.
  10447.  
  10448. note
  10449.  
  10450. The example illustrates end condition functions. An abstraction should be
  10451. automatically initialized before its user gets a chance to damage it. When
  10452. that is not possible, it should be supplied with initialization operations. In
  10453. any case, it needs finalization operations.  Where possible, query operations
  10454. should be provided to determine when limits are about to be exceeded, so that
  10455. the user can avoid causing exceptions to be raised.
  10456.  
  10457. It is also useful to provide reset operations for many objects. To see that a
  10458. reset and an initiation can be different, consider the analogous situation of
  10459. a "warm boot" and a "cold boot" on a personal computer.
  10460.  
  10461. Even if all of these operations are not appropriate for the abstraction, the 
  10462. exercise of considering them aids in formulating a complete set of operations, 
  10463. others of which may be used by another application.
  10464.  
  10465. Some implementations of the language link all subprograms of a package into
  10466. the executable file, ignoring whether they are used or not, making unused
  10467. operations a liability (see Guideline ). In such cases, where the overhead is
  10468. significant, create a copy of the fully functional part and comment out the
  10469. unused operations with an indication that they are redundant in this
  10470. application.
  10471.  
  10472. 8.3.2   Generic Units
  10473.  
  10474. guideline
  10475.  
  10476. o       Use generic units to avoid code duplication.
  10477.  
  10478. o       Parameterize generic units for maximum adaptability.
  10479.  
  10480. o       Reuse common instantiations of generic units, as well as the generic 
  10481. units themselves.
  10482.  
  10483. rationale
  10484.  
  10485. Ada does not allow subprograms or data types to be passed as actual parameters 
  10486. to subprograms during execution. Such parameters must be specified as generic 
  10487. formal parameters to a generic unit when it is instantiated. Therefore, if you 
  10488. want to write a subprogram for which there is variation from call to call in 
  10489. the data type of objects on which it operates, or in the subprogram which it 
  10490. calls, then you must write the subprogram as a generic unit and instantiate it 
  10491. once for each combination of data type and subprogram parameters. The 
  10492. instantiations of the unit can then be called as regular subprograms.
  10493.  
  10494. If you find yourself writing two very similar routines differing only in the 
  10495. data type they operate on or the subprograms they call, then it is probably 
  10496. better to write the routine once as a generic unit and instantiate it twice to 
  10497. get the two versions you need. When the need arises later to modify the two 
  10498. routines, the change only needs to be made in one place. This greatly 
  10499. facilitates maintenance.
  10500.  
  10501. Once you have made such a choice, consider other aspects of the routine that
  10502. these two instances may have in common but which are not essential to the
  10503. nature of the routine. Factor these out as generic formal parameters. When the
  10504. need arises later for a third similar routine, it can be automatically
  10505. produced by a third instantiation, if you have foreseen all the differences
  10506. between it and the other two. A parameterized generic unit can be very
  10507. reusable.
  10508.  
  10509. It may seem that the effort involved in writing generic rather than nongeneric
  10510. units is substantial. However, making units generic is not much more difficult
  10511. or time-consuming than making them nongeneric once you become familiar with
  10512. the generic facilities. It is, for the most part, a matter of practice. Also,
  10513. any effort put into the development of the unit will be recouped when the unit
  10514. is reused, as it surely will be if it is placed in a reuse library with
  10515. sufficient visibility. Do not limit your thinking about potential reuse to the
  10516. application you are working on or to other applications with which you are
  10517. very familiar.  Applications with which you are not familiar or future
  10518. applications might be able to reuse your software.
  10519.  
  10520. After writing a generic unit and placing it in your reuse library, the first
  10521. thing you are likely to do is to instantiate it once for your particular
  10522. needs.  At this time, it is a good idea to consider whether there are
  10523. instantiations which are very likely to be widely used. If so, place each such
  10524. instantiation in your reuse library so that they can be found and shared by
  10525. others.
  10526.  
  10527. 8.3.3   Using Generic Units to Encapsulate Algorithms
  10528.  
  10529. guideline
  10530.  
  10531. o       Use generic units to encapsulate algorithms independently of data type.
  10532.  
  10533. example
  10534.  
  10535. This is the specification of a generic sort procedure:
  10536.  
  10537. ------------------------------------------------------------------------
  10538. generic
  10539.  
  10540.    type Element is limited private;
  10541.    type Data    is array (Positive range <>) of Element;
  10542.  
  10543.    with function  "<"  (Left  : in     Element;
  10544.             Right : in     Element)
  10545.             return         Boolean  is <>;
  10546.    with procedure Swap (Left  : in out Element;
  10547.             Right : in out Element) is <>;
  10548.  
  10549. procedure Generic_Sort (Data_To_Sort : in out Data);
  10550. ------------------------------------------------------------------------
  10551.  
  10552. The generic body looks just like a regular procedure body and can make full
  10553. use of the generic formal parameters in implementing the sort algorithm:
  10554.  
  10555. ------------------------------------------------------------------------
  10556. procedure Generic_Sort (Data_To_Sort : in out Data) is
  10557. begin
  10558.    ...
  10559.    for I in Data_To_Sort'Range loop
  10560.       ...
  10561.  
  10562.      ...
  10563.      if Data_To_Sort(J) < Data_To_Sort(I) then
  10564.         Swap(Data_To_Sort(I), Data_To_Sort(J));
  10565.      end if;
  10566.  
  10567.      ...
  10568.       ...
  10569.    end loop;
  10570.  
  10571.    ...
  10572. end Generic_Sort;
  10573. ------------------------------------------------------------------------
  10574.  
  10575. The generic procedure can be instantiated as:
  10576.  
  10577.    type Integer_Array is array (Positive range <>) of Integer;
  10578.  
  10579.    procedure Swap (Left  : in out Integer;
  10580.            Right : in out Integer);
  10581.  
  10582.    procedure Sort is
  10583.       new Generic_Sort (Element => Integer,
  10584.                 Data    => Integer_Array);
  10585.  
  10586. or
  10587.  
  10588.    subtype String_80    is String (1 .. 80);
  10589.    type    String_Array is array (Positive range <>) of String_80;
  10590.  
  10591.    procedure Swap (Left  : in out String_80;
  10592.            Right : in out String_80);
  10593.    procedure Sort is
  10594.       new Generic_Sort (Element => String_80,
  10595.             Data    => String_Array);
  10596.  
  10597. and called as:
  10598.  
  10599.    Integer_Array_1 : Integer_Array (1 .. 100);
  10600.    ...
  10601.    Sort(Integer_Array_1);
  10602.  
  10603. or
  10604.  
  10605.    String_Array_1  : String_Array  (1 .. 100);
  10606.    ...
  10607.    Sort(String_Array_1);
  10608.  
  10609. rationale
  10610.  
  10611. A sort algorithm can be described independently of the data type being sorted.
  10612. This generic procedure takes the Element data type as a generic limited
  10613. private type parameter so that it assumes as little as possible about the data
  10614. type of the objects actually being operated on. It also takes Data as a
  10615. generic formal parameter so that instantiations can have entire arrays passed
  10616. to them for sorting. Finally, it explicitly requires the two operators that it
  10617. needs to do the sort: comparison and swap.The sort algorithm is encapsulated
  10618. without reference to any data type. The generic can be instantiated to sort an
  10619. array of any data type.
  10620.  
  10621. 8.3.4   Using Generic Units for Abstract Data Types
  10622.  
  10623. guideline
  10624.  
  10625. o       Use abstract data types in preference to abstract data objects.
  10626.  
  10627. o       Use generic units to implement abstract data types independently of 
  10628. their component data type.
  10629.  
  10630. example
  10631.  
  10632. This example presents a series of different techniques which can be used to
  10633. generate abstract data types and objects. A discussion of the merits of each
  10634. follows in the rationale section below. The first is an abstract data object
  10635. (ADO), also known as an abstract state machine (ASM). It encapsulates one
  10636. stack of integers.
  10637.  
  10638. ------------------------------------------------------------------------
  10639. package Bounded_Stack is
  10640.  
  10641.    subtype Element is Integer;
  10642.    Maximum_Stack_Size : constant := 100;
  10643.  
  10644.    procedure Push (New_Element : in     Element);
  10645.    procedure Pop  (Top_Element :    out Element);
  10646.  
  10647.    Overflow  : exception;
  10648.    Underflow : exception;
  10649.    ...
  10650.  
  10651. end Bounded_Stack;
  10652. ------------------------------------------------------------------------
  10653.  
  10654. The second is an abstract data type (ADT). It differs from the ADO by
  10655. exporting the Stacks type, which allows the user to declare any number of
  10656. stacks of integers. Note that since multiple stacks may now exist, it is
  10657. necessary to specify a Stack argument on calls to Push and Pop.
  10658.  
  10659. ------------------------------------------------------------------------
  10660. package Bounded_Stack is
  10661.  
  10662.    subtype Element is Integer;
  10663.    type    Stack   is limited private;
  10664.  
  10665.    Maximum_Stack_Size : constant := 100;
  10666.  
  10667.    procedure Push (On_Top      : in out Stack;
  10668.            New_Element : in     Element);
  10669.    procedure Pop  (From_Top    : in out Stack;
  10670.            Top_Element :    out Element);
  10671.  
  10672.    Overflow  : exception;
  10673.    Underflow : exception;
  10674.  
  10675.    ...
  10676. private
  10677.    type Stack_Information;
  10678.    type Stack is access Stack_Information;
  10679.  
  10680. end Bounded_Stack;
  10681. ------------------------------------------------------------------------
  10682.  
  10683. The third is a parameterless generic abstract data object (GADO). It differs 
  10684. from the ADO (the first example) simply by being generic, so that the user can 
  10685. instantiate it multiple times to obtain multiple stacks of integers.
  10686.  
  10687. ------------------------------------------------------------------------
  10688. generic
  10689. package Bounded_Stack is
  10690.  
  10691.    subtype Element is Integer;
  10692.  
  10693.    Maximum_Stack_Size : constant := 100;
  10694.  
  10695.    procedure Push (New_Element : in     Element);
  10696.    procedure Pop  (Top_Element :    out Element);
  10697.  
  10698.    Overflow  : exception;
  10699.    Underflow : exception;
  10700.    ...
  10701.  
  10702. end Bounded_Stack;
  10703. ------------------------------------------------------------------------
  10704.  
  10705. The fourth is a slight variant on the third, still a generic abstract data
  10706. object (GADO) but with parameters. It differs from the third example by making
  10707. the data type of the stack a generic parameter so that stacks of data types
  10708. other than Integer can be created. Also, Max_Stack_Size has been made a
  10709. generic parameter which defaults to 100 but can be specified by the user,
  10710. rather than a constant defined by the package.
  10711.  
  10712. ------------------------------------------------------------------------
  10713. generic
  10714.  
  10715.    type Element is limited private;
  10716.  
  10717.    with procedure Assign (From : in     Element;
  10718.               To   : in out Element);
  10719.  
  10720.    Maximum_Stack_Size : in     Natural := 100;
  10721.  
  10722. package Bounded_Stack is
  10723.  
  10724.    procedure Push (New_Element : in     Element);
  10725.    procedure Pop  (Top_Element : in out Element);
  10726.  
  10727.    Overflow  : exception;
  10728.    Underflow : exception;
  10729.    ...
  10730.  
  10731. end Bounded_Stack;
  10732. ------------------------------------------------------------------------
  10733.  
  10734. Finally, the fifth is a generic abstract data type (GADT). It differs from the 
  10735. GADO in the fourth example in the same way that the ADT in the second example 
  10736. differed from the ADO in the first example; it exports the Stacks type, which 
  10737. allows the user to declare any number of stacks.
  10738.  
  10739. ------------------------------------------------------------------------
  10740. generic
  10741.  
  10742.    type Element is limited private;
  10743.  
  10744.    with procedure Assign (From : in     Element;
  10745.               To   : in out Element);
  10746.  
  10747.    Maximum_Stack_Size : in     Natural := 100;
  10748.  
  10749. package Bounded_Stack is
  10750.  
  10751.    type Stack is limited private;
  10752.  
  10753.    procedure Push (On_Top      : in out Stack;
  10754.            New_Element : in     Element);
  10755.    procedure Pop  (From_Top    : in out Stack;
  10756.            Top_Element : in out Element);
  10757.  
  10758.    Overflow  : exception;
  10759.    Underflow : exception;
  10760.    ...
  10761.  
  10762. private
  10763.    type Stack_Information;
  10764.    type Stack is access Stack_Information;
  10765. end Bounded_Stack;
  10766. ------------------------------------------------------------------------
  10767.  
  10768. rationale
  10769.  
  10770. The biggest advantage of an ADT over an ADO (or a GADT over a GADO) is that
  10771. the user of the package can declare as many objects as desired with an ADT.
  10772. These objects can be declared as standalone variables or as components of
  10773. arrays and records. They can also be passed as parameters. None of this is
  10774. possible with an ADO, where the single data object is encapsulated inside of
  10775. the package.  Furthermore, an ADO provides no more protection of the data
  10776. structure than an ADT. When a private type is exported by the ADT package, as
  10777. in the example above, then for both the ADO and ADT, the only legal operations
  10778. which can modify the data are those defined explicitly by the package (in this
  10779. case, Push and Pop). For these reasons, an ADT or GADT is almost always
  10780. preferable to an ADO or GADO, respectively.
  10781.  
  10782. A GADO is similar to an ADT in one way: it allows multiple objects to be
  10783. created by the user. With an ADT, multiple objects can be declared using the
  10784. type defined by the ADT package. With a GADO (even a GADO with no generic
  10785. formal parameters, as shown in the third example), the package can be
  10786. instantiated multiple times to produce multiple objects. However, the
  10787. similarity ends there. The multiple objects produced by the instantiations
  10788. suffer from all restrictions described above for ADOs; they cannot be used in
  10789. arrays or records or passed as parameters. Furthermore, the objects are each
  10790. of a different type, and no operations are defined to operate on more than one
  10791. of them at a time. For example, there cannot be an operation to compare two
  10792. such objects or to assign one to another. The multiple objects declared using
  10793. the type defined by an ADT package suffer from no such restrictions; they can
  10794. be used in arrays and records and can be passed as parameters.  Also, they are
  10795. all declared to be of the same type, so that it is possible for the ADT
  10796. package to provide operations to assign, compare, copy, etc. For these
  10797. reasons, an ADT is almost always preferable to a parameterless GADO.
  10798.  
  10799. The biggest advantage of a GADT or GADO over an ADT or ADO, respectively, is
  10800. that the GADT and GADO are generic and can thus be parameterized with types,
  10801. subprograms, and other configuration information. Thus, as shown above, a
  10802. single generic package can support bounded stacks of any data type and any
  10803. stack size, while the ADT and ADO above are restricted to stacks of Integer,
  10804. no more than 100 in size. For this reason, a GADO or GADT is almost always
  10805. preferable to an ADO or ADT.
  10806.  
  10807. The list of examples above is given in order of increasing power and 
  10808. flexibility, starting with an ADO and ending with a GADT. These advantages are 
  10809. not expensive in terms of complexity or development time. The specification of 
  10810. the GADT above is not significantly harder to write or understand than the 
  10811. specification of the ADO. The bodies are also nearly identical. Compare the 
  10812. body for the simplest version, the ADO:
  10813.  
  10814. ------------------------------------------------------------------------
  10815. package body Bounded_Stack is
  10816.  
  10817.    type Stack_Slots is array (Natural range <>) of Element;
  10818.  
  10819.    type Stack_Information is
  10820.       record
  10821.      Slots : Stack_Slots (1 .. Maximum_Stack_Size);
  10822.      Index : Natural                              := 0;
  10823.       end record;
  10824.  
  10825.    Stack : Stack_Information;
  10826.  
  10827.    ---------------------------------------------------------------------
  10828.    procedure Push (New_Element : in     Element) is
  10829.    begin
  10830.       if Stack.Index >= Maximum_Stack_Size then
  10831.      raise Overflow;
  10832.       end if;
  10833.  
  10834.       Stack.Index := Stack.Index + 1;
  10835.       Stack.Slots(Stack.Index) := New_Element;
  10836.    end Push;
  10837.  
  10838.    ---------------------------------------------------------------------
  10839.    procedure Pop (Top_Element :    out Element) is
  10840.    begin
  10841.       if Stack.Index <= 0 then
  10842.      raise Underflow;
  10843.       end if;
  10844.  
  10845.       Top_Element := Stack.Slots(Stack.Index);
  10846.       Stack.Index := Stack.Index - 1;
  10847.    end Pop;
  10848.    ---------------------------------------------------------------------
  10849.  
  10850.    ...
  10851. end Bounded_Stack;
  10852. ------------------------------------------------------------------------
  10853.  
  10854. with the body for the most powerful and flexible version, the GADT:
  10855.  
  10856. ------------------------------------------------------------------------
  10857. package body Bounded_Stack is
  10858.  
  10859.    type Stack_Slots is array (Natural range <>) of Element;
  10860.  
  10861.    type Stack_Information is
  10862.       record
  10863.      Slots : Stack_Slots (1 .. Maximum_Stack_Size);
  10864.      Index : Natural                               := 0;
  10865.       end record;
  10866.  
  10867.    ---------------------------------------------------------------------
  10868.    procedure Push (On_Top      : in out Stack;
  10869.            New_Element : in     Element) is
  10870.    begin
  10871.       if On_Top.Index >= Maximum_Stack_Size then
  10872.      raise Overflow;
  10873.       end if;
  10874.  
  10875.       On_Top.Index := On_Top.Index + 1;
  10876.       Assign(From => New_Element,
  10877.          To   => On_Top.Slots(On_Top.Index));
  10878.    end Push;
  10879.  
  10880.    ---------------------------------------------------------------------
  10881.    procedure Pop (From_Top    : in out Stack;
  10882.           Top_Element : in out Element) is
  10883.    begin
  10884.       if From_Top.Index <= 0 then
  10885.      raise Underflow;
  10886.       end if;
  10887.  
  10888.       Assign(From => From_Top.Slots(From_Top.Index),
  10889.          To   => Top_Element);
  10890.       From_Top.Index := From_Top.Index - 1;
  10891.    end Pop;
  10892.    ---------------------------------------------------------------------
  10893.  
  10894.    ...
  10895. end Bounded_Stack;
  10896. ------------------------------------------------------------------------
  10897.  
  10898. There are only two differences. First, the ADO declares a local object called 
  10899. Stack, while the GADT has one additional parameter (called Stack) on each of 
  10900. the exported procedures Push and Pop. Second, the GADT uses the Assign 
  10901. procedure rather than the assignment operator ":=" because the generic formal
  10902. type Element was declared limited private. This second difference could have 
  10903. been avoided by declaring Element as private, but this is not recommended 
  10904. because it reduces the composability of the generic reusable part.
  10905.  
  10906. note
  10907.  
  10908. The predefined simple types will need an assign or equality operation when
  10909. used to instantiate generics that expect limited private types.  Although it
  10910. is a nuisance, it is simple enough for the few times it would apply.
  10911.  
  10912. 8.3.5   Iterators
  10913.  
  10914. guideline
  10915.  
  10916. o       Provide iterators for traversing complex data structures within 
  10917. reusable parts.
  10918.  
  10919. o       Provide both active and passive iterators.
  10920.  
  10921. o       Protect the iterators from errors due to modification of the data 
  10922. structure during iteration.
  10923.  
  10924. o       Document the behavior of the iterators when the data structure is 
  10925. modified during traversal.
  10926.  
  10927. example
  10928.  
  10929. The following package defines an abstract list data type, with both active and 
  10930. passive iterators for traversing a list.
  10931.  
  10932. ------------------------------------------------------------------------
  10933. generic
  10934.  
  10935.    type Element is limited private;
  10936.    ...
  10937.  
  10938. package Unbounded_List is
  10939.  
  10940.    type List is limited private;
  10941.    procedure Insert (New_Element : in     Element;
  10942.              Into        : in out List);
  10943.  
  10944.    -- Passive (generic) iterator.
  10945.    generic
  10946.  
  10947.       with procedure Process (Each : in out Element);
  10948.  
  10949.    procedure Iterate (Over : in     List);
  10950.  
  10951.    -- Active iterator
  10952.    type Iterator is limited private;
  10953.    procedure Initialize (Index         : in out Iterator;
  10954.              Existing_List : in     List);
  10955.    function  More       (Index         : in     Iterator)
  10956.              return                 Boolean;
  10957.    procedure Advance    (Index         : in out Iterator);
  10958.    function  Current    (Index         : in     Iterator)
  10959.              return                 Element;
  10960.    procedure Finalize   (Index         : in out Iterator);
  10961.  
  10962.    ...
  10963. private
  10964.    ...
  10965. end Unbounded_List;
  10966. ------------------------------------------------------------------------
  10967.  
  10968. After instantiating the generic package, and declaring a list, as:
  10969.  
  10970. ------------------------------------------------------------------------
  10971. with Unbounded_List;
  10972. procedure List_User is
  10973.  
  10974.    type Employee is ...;
  10975.  
  10976.    package Roster is
  10977.       new Unbounded_List (Element => Employee, ...);
  10978.  
  10979.    Employee_List : Roster.List;
  10980.  
  10981.  
  10982.  
  10983. the passive iterator is instantiated, specifying the name of the routine which 
  10984. should be called for each list element when the iterator is called.
  10985.  
  10986.    ---------------------------------------------------------------------
  10987.    procedure Process_Employee (Each : in out Employee) is
  10988.    begin
  10989.       ...
  10990.       -- Perform the required action for EMPLOYEE here.
  10991.    end Process_Employee;
  10992.    ---------------------------------------------------------------------
  10993.  
  10994.    procedure Process_All is
  10995.      new Roster.Iterate (Process => Process_Employee);
  10996.  
  10997. The passive iterator can then be called, as:
  10998.  
  10999. begin  -- List_User
  11000.    Process_All(Employee_List);
  11001. end List_User;
  11002. ------------------------------------------------------------------------
  11003.  
  11004. Alternatively, the active iterator can be used, without the second 
  11005. instantiation required by the passive iterator, as:
  11006.  
  11007.    Iterator      : Roster.Iterator;
  11008.  
  11009.    procedure Process_Employee (Each : in     Employee) is separate;
  11010.  
  11011. begin  -- List_User
  11012.    Roster.Initialize (Index         => Iterator,
  11013.               Existing_List => Employee_List);
  11014.    while Roster.More(Iterator) loop
  11015.       Process_Employee(Each => Roster.Current(Iterator));
  11016.       Roster.Advance(Iterator);
  11017.    end loop;
  11018.  
  11019.    Roster.Finalize(Iterator);
  11020. end List_User;
  11021. ------------------------------------------------------------------------
  11022.  
  11023. rationale
  11024.  
  11025. Iteration over complex data structures is often required and, if not provided
  11026. by the part itself, can be difficult to implement without violating
  11027. information hiding principles.
  11028.  
  11029. Active and passive iterators each have their advantages, but neither is 
  11030. appropriate in all situations. Therefore, it is recommended that both be 
  11031. provided to give the user a choice of which to use in each situation.
  11032.  
  11033. Passive iterators are simpler and less error-prone than active iterators, in
  11034. the same way that the for loop is simpler and less error-prone than the while
  11035. loop. There are fewer mistakes that the user can make in using a passive
  11036. iterator. Simply instantiate it with the routine to be executed for each list
  11037. element, and call the instantiation for the desired list. Active iterators
  11038. require more care by the user. The iterator must be declared, then initialized
  11039. with the desired list, then Current and Advance must be called in a loop until
  11040. More returns false, then the iterator must be terminated. Care must be taken
  11041. to perform these steps in the proper sequence. Care must also be taken to
  11042. associate the proper iterator variable with the proper list variable. It is
  11043. possible for a change made to the software during maintenance to introduce an
  11044. error, perhaps an infinite loop.
  11045.  
  11046. On the other hand, active iterators are more flexible than passive iterators.
  11047. With a passive iterator, it is difficult to perform multiple, concurrent,
  11048. synchronized iterations. For example, it is much easier to use active
  11049. iterators to iterate over two sorted lists, merging them into a third sorted
  11050. list. Also, for multidimensional data structures, a small number of active
  11051. iterator routines may be able to replace a large number of passive iterators,
  11052. each of which implements one combination of the active iterators. Consider,
  11053. for example, a binary tree. In what order should the passive iterator visit
  11054. the nodes? Depth first? Breadth first? What about the need to do a binary
  11055. search of the tree? Each of these could be implemented as a passive iterator,
  11056. but it may make more sense to simply define the More_Left, More_Right,
  11057. Advance_Left, and Advance_Right routines required by the active iterator to
  11058. cover all combinations.Finally, active iterators can be passed as generic
  11059. formal parameters while passive iterators cannot because passive iterators are
  11060. themselves generic, and generic units cannot be passed as parameters to other
  11061. generic units.
  11062.  
  11063. For either type of iterator, semantic questions can arise about what happens
  11064. when the data structure is modified as it is being iterated. When writing an
  11065. iterator, be sure to consider this possibility, and indicate with comments the
  11066. behavior which occurs in such a case. It is not always obvious to the user
  11067. what to expect. For example, to determine the "closure" of a mathematical
  11068. "set" with respect to some operation, a common algorithm is to iterate over
  11069. the members of the set, generating new elements and adding them to the set. In
  11070. such a case, it is important that elements added to the set during the
  11071. iteration be encountered subsequently during the iteration. On the other hand,
  11072. for other algorithms it may be important that the set which it iterated is the
  11073. set as it existed at the beginning of the iteration. In the case of a
  11074. prioritized list data structure, if the list is iterated in priority order, it
  11075. may be important that elements inserted at lower priority than the current
  11076. element during iteration not be encountered subsequently during the iteration,
  11077. but that elements inserted at a higher priority should be encountered. In any
  11078. case, make a conscious decision about how the iterator should operate, and
  11079. document that behavior in the package specification.
  11080.  
  11081. Deletions from the data structure also pose a problem for iterators. It is a 
  11082. common mistake for a user to iterate over a data structure, deleting it piece 
  11083. by piece during the iteration. If the iterator is not prepared for such a 
  11084. situation, it is possible to end up dereferencing a null pointer or committing 
  11085. a similar error. Such situations can be prevented by storing extra information 
  11086. with each data structure which indicates whether it is currently being 
  11087. iterated, and using this information to disallow any modifications to the data 
  11088. structure during iteration. When the data structure is declared as a limited 
  11089. private type, as should usually be the case when iterators are involved, the 
  11090. only operations defined on the type are declared explicitly in the package 
  11091. which declares the type, making it possible to add such tests to all 
  11092. modification operations.
  11093.  
  11094. note
  11095.  
  11096. For further discussion of passive and active iterators see Ross (1989) and 
  11097. Booch (1987).
  11098.  
  11099. 8.3.6   Private and Limited Private Types
  11100.  
  11101. guideline
  11102.  
  11103. o       Use limited private (not private) for generic formal types, explicitly 
  11104. importing assignment and equality operations if required.
  11105.  
  11106. o       Export the least restrictive type that maintains the integrity of the 
  11107. data and abstraction while allowing alternate implementations.
  11108.  
  11109. o       Use mode in out rather than out for parameters of a generic formal 
  11110. subprogram, when the parameters are of an imported limited type.
  11111.  
  11112. example
  11113.  
  11114. The first example violates the guideline by having private (nonlimited)
  11115. generic formal types.
  11116.  
  11117. ------------------------------------------------------------------------
  11118. generic
  11119.  
  11120.    type Item is private;
  11121.    type Key  is private;
  11122.  
  11123.    with function Key_Of (Current : in     Item) return Key;
  11124.  
  11125. package List_Manager is
  11126.  
  11127.    type List is limited private;
  11128.  
  11129.    procedure Insert   (Into     : in     List;
  11130.                New_Item : in     Item);
  11131.    procedure Retrieve (From     : in     List;
  11132.                Using    : in     Key;
  11133.                Match    : in out Item);
  11134.  
  11135. private
  11136.    type List is ...
  11137. end List_Manager;
  11138. ------------------------------------------------------------------------
  11139.  
  11140. The second example is improved by using limited private generic formal types 
  11141. and importing the assignment operation for Item and the equality operator for 
  11142. Key.
  11143.  
  11144. ------------------------------------------------------------------------
  11145. generic
  11146.  
  11147.    type Item is limited private;
  11148.    type Key  is limited private;
  11149.  
  11150.    with procedure Assign (From    : in     Item;
  11151.               To      : in out Item);
  11152.    with function "="     (Left    : in     Key;
  11153.               Right   : in     Key)
  11154.               return           Boolean;
  11155.    with function Key_Of  (Current : in     Item)
  11156.               return           Key;
  11157.  
  11158. package List_Manager is
  11159.  
  11160.    type List is limited private;
  11161.  
  11162.    procedure Insert   (Into     : in     List;
  11163.                New_Item : in     Item);
  11164.    procedure Retrieve (From     : in     List;
  11165.                Using    : in     Key;
  11166.                Match    : in out Item);
  11167.  
  11168. private
  11169.    type List is ...
  11170. end List_Manager;
  11171. ------------------------------------------------------------------------
  11172.  
  11173. rationale
  11174.  
  11175. For a generic component to be usable in as many contexts as possible, it
  11176. should minimize the assumptions that it makes about its environment and should
  11177. make explicit any assumptions that are necessary. In Ada, the assumptions made
  11178. by generic units can be stated explicitly by the types of the generic formal
  11179. parameters. A limited private generic formal type prevents the generic unit
  11180. from making any assumptions about the structure of objects of the type or
  11181. about operations defined for such objects. A private (nonlimited) generic
  11182. formal type allows the assumption that assignment and equality comparison
  11183. operations are defined for the type. Thus, a limited private data type cannot
  11184. be specified as the actual parameter for a private generic formal type.
  11185.  
  11186. Therefore, generic formal types should almost always be limited private rather
  11187. than just private. This restricts the operations available on the imported
  11188. type within the generic unit body but provides maximum flexibility for the
  11189. user of the generic unit. Any operations required by the generic body should
  11190. be explicitly imported as generic formal subprograms. In the second example
  11191. above, only the operations required for managing a list of items with keys are
  11192. imported: Assign provides the ability to store items in the list, and Key_Of
  11193. and "=" support determination and comparison of keys during retrieval
  11194. operations. No other operations are required to manage the list. Specifically,
  11195. there is no need to be able to assign keys or compare entire items for
  11196. equality. Those operations would have been implicitly available if a private
  11197. type had been used for the generic formal type, and any actual type for which
  11198. they were not defined could not have been used with this generic unit.
  11199.  
  11200. The situation is reversed for types exported by a reusable part. For exported 
  11201. types, the restrictions specified by limited and limited private are 
  11202. restrictions on the user of the part, not on the part itself. To provide 
  11203. maximum capability to the user of a reusable part, export types with as few 
  11204. restrictions as possible. Apply restrictions as necessary to protect the 
  11205. integrity of the exported data structures and the abstraction for the various 
  11206. implementations envisioned for that generic.
  11207.  
  11208. In the example above, the List type is exported as limited private to hide the
  11209. details of the list implementation and protect the structure of a list.
  11210. Limited private is chosen over private to prevent the user from being able to
  11211. use the predefined assignment operation. This is important if the list is
  11212. implemented as an access type pointing to a linked lists of records, because
  11213. the predefined assignment would make copies of the pointer, not copies of the
  11214. entire list, which the user may not realize. If it is expected that the user
  11215. needs the ability to copy lists, then a copy operation should be explicitly
  11216. exported.
  11217.  
  11218. Because they are so restrictive, limited private types are not always the best
  11219. choice for types exported by a reusable part. In a case where it makes sense
  11220. to allow the user to make copies of and compare data objects, and when the
  11221. underlying data type does not involve access types (so that the entire data
  11222. structure gets copied or compared), then it is better to export a (nonlimited)
  11223. private type. In cases where it does not detract from the abstraction to
  11224. reveal even more about the type, then a nonprivate type (e.g., a numeric,
  11225. enumerated, record, or array type) should be used.
  11226.  
  11227. For cases where limited private types are exported, the package should
  11228. explicitly provide equality and assignment operations, if appropriate to the
  11229. abstraction. Limited private is almost always appropriate for types
  11230. implemented as access types. In such cases, predefined equality is seldom the
  11231. most desirable semantics. In such cases, also consider providing both forms of
  11232. assignment (assignment of a reference and assignment of a copy).
  11233.  
  11234. When the parameters are of an imported limited type, using mode in out instead
  11235. of out for parameters of a generic formal subprogram is important for the
  11236. following reason. Ada allows an out mode parameter of a limited private type
  11237. on a subprogram only when the subprogram is declared in the visible part of
  11238. the package that declares the private type. See Section 7.4.4(4) of the Ada
  11239. Language Reference Manual (Department of Defense 1983).There is no such
  11240. restriction in parameters of mode in out.The result of this is that if you
  11241. define a generic with a limited generic formal type and a generic formal
  11242. subprogram with an out parameter of that type, then the generic can only be
  11243. instantiated with a limited private actual type if the package which declares
  11244. that type also declares a subprogram with exactly the same profile (number and
  11245. types or arguments and return value) as your generic formal subprogram. A
  11246. potential user who wants to instantiate your generic with a limited type
  11247. defined in another package will not be able to write a subprogram to pass as
  11248. the generic actual.
  11249.  
  11250. note
  11251.  
  11252. It is possible (but clumsy) to redefine equality for nonlimited types.
  11253. However, if a generic imports a (nonlimited) private type and uses equality,
  11254. it will automatically use the predefined equality and not the user-supplied
  11255. redefinition. This is another argument for using limited private generic
  11256. formal parameters.
  11257.  
  11258. It should also be noted that the predefined packages, Sequential_IO and 
  11259. Direct_IO, take private types.  This will complicate IO requirements for 
  11260. limited private types and should be considered during design.
  11261.  
  11262. 8.4     INDEPENDENCE
  11263.  
  11264. A reusable part should be as independent as possible from other reusable
  11265. parts.  A potential user is less inclined to reuse a part if that part
  11266. requires the use of other parts which seem unnecessary. The "extra baggage" of
  11267. the other parts wastes time and space. A user would like to be able to reuse
  11268. only that part which is perceived as useful.
  11269.  
  11270. Note that the concept of a "part" is intentionally vague here. A single
  11271. package does not need to be independent of each other package in a reuse
  11272. library, if the "parts" from that library which are typically reused are
  11273. entire subsystems.  If the entire subsystem is perceived as providing a useful
  11274. function, the entire subsystem is reused. However, the subsystem should not be
  11275. tightly coupled to all the other subsystems in the reuse library, so that it
  11276. is difficult or impossible to reuse the subsystem without reusing the entire
  11277. library. Coupling between reusable parts should only occur when it provides a
  11278. strong benefit perceptible to the user.
  11279.  
  11280. 8.4.1   Using Generic Parameters to Reduce Coupling
  11281.  
  11282. guideline
  11283.  
  11284. o       Minimize with clauses on reusable parts, especially on their 
  11285. specifications.
  11286.  
  11287. o       Use generic parameters instead of with statements to reduce the number 
  11288. of context clauses on a reusable part.
  11289.  
  11290. o    Use generic parameters instead of with statements to import portions
  11291. of a package rather than the entire package.
  11292.  
  11293. example
  11294.  
  11295. A procedure like the following:
  11296.  
  11297. ------------------------------------------------------------------------
  11298. with Package_A;
  11299. procedure Produce_And_Store_A is
  11300.    ...
  11301.  
  11302. begin  -- Produce_And_Store_A
  11303.    ...
  11304.    Package_A.Produce (...);
  11305.  
  11306.    ...
  11307.    Package_A.Store (...);
  11308.  
  11309.    ...
  11310. end Produce_And_Store_A;
  11311. ------------------------------------------------------------------------
  11312.  
  11313. can be rewritten as a generic unit:
  11314.  
  11315. ------------------------------------------------------------------------
  11316. generic
  11317.  
  11318.    with procedure Produce (...);
  11319.    with procedure Store   (...);
  11320.  
  11321. procedure Produce_And_Store;
  11322.  
  11323. ------------------------------------------------------------------------
  11324. procedure Produce_And_Store is
  11325.    ...
  11326.  
  11327. begin  -- Produce_And_Store
  11328.    ...
  11329.    Produce (...);
  11330.  
  11331.    ...
  11332.    Store   (...);
  11333.  
  11334.    ...
  11335. end Produce_And_Store;
  11336. ------------------------------------------------------------------------
  11337.  
  11338. and then instantiated:
  11339.  
  11340. ------------------------------------------------------------------------
  11341. with Package_A;
  11342. with Produce_And_Store;
  11343. procedure Produce_And_Store_A is
  11344.     new Produce_And_Store (Produce => Package_A.Produce,
  11345.                    Store   => Package_A.Store);
  11346. ------------------------------------------------------------------------
  11347.  
  11348. rationale
  11349.  
  11350. Context (with) clauses specify the names of other units upon which this unit
  11351. depends. Such dependencies cannot and should not be entirely avoided, but it
  11352. is a good idea to minimize the number of them which occur in the specification
  11353. of a unit. Try to move them to the body, leaving the specification independent
  11354. of other units so that it is easier to understand in isolation. Also, organize
  11355. your reusable parts in such a way that the bodies of the units do not contain
  11356. large numbers of dependencies on each other. Partitioning your library into
  11357. independent functional areas with no dependencies spanning the boundaries of
  11358. the areas is a good way to start. Finally, reduce dependencies by using
  11359. generic formal parameters instead of with statements, as shown in the example
  11360. above. If the units in a library are too tightly coupled, then no single part
  11361. can be reused without reusing most or all of the library.
  11362.  
  11363. The first (nongeneric) version of Produce_And_Store_A above is difficult to
  11364. reuse because it depends on Package_A which may not be general purpose or
  11365. generally available. If the operation Produce_And_Store has reuse potential
  11366. which is reduced by this dependency, a generic unit and an instantiation
  11367. should be produced as shown above. Note that the with clause for Package_A has
  11368. been moved from the Produce_And_Store generic procedure which encapsulates the
  11369. reusable algorithm to the Produce_And_Store_A instantiation. Instead of naming
  11370. the package which provides the required operations, the generic unit simply
  11371. lists the required operations themselves. This increases the independence and
  11372. reusability of the generic unit.
  11373.  
  11374. This use of generic formal parameters in place of with clauses also allows
  11375. visibility at a finer granularity. The with clause on the nongeneric version
  11376. of Produce_And_Store_A makes all of the contents of Package_A visible to
  11377. Produce_And_Store_A, while the generic parameters on the generic version make
  11378. only the Produce and Store operations available to the generic instantiation.
  11379.  
  11380. 8.4.2   Coupling Due to Pragmas
  11381.  
  11382. guideline
  11383.  
  11384. o       For nongenerics named in a context clause, avoid pragma Elaborate.
  11385.  
  11386. o       Use pragma Elaborate for generics named in a context clause.
  11387.  
  11388. o       Avoid pragma Priority in tasks hidden in reusable parts.
  11389.  
  11390. example
  11391.  
  11392. ------------------------------------------------------------------------
  11393. generic
  11394.    ...
  11395.  
  11396. package Stack is
  11397.    ...
  11398.  
  11399. end Stack;
  11400.  
  11401. ------------------------------------------------------------------------
  11402. with Stack;
  11403. pragma Elaborate (Stack); -- in case the body is not yet elaborated
  11404. package My_Stack is
  11405.     new Stack (...);
  11406.  
  11407. ------------------------------------------------------------------------
  11408. package body Stack is
  11409. begin
  11410.    ...
  11411. end Stack;
  11412. ------------------------------------------------------------------------
  11413.  
  11414. rationale
  11415.  
  11416. Pragma Elaborate controls the order of elaboration of one unit with respect to 
  11417. another. This is another way of coupling units and should be avoided when 
  11418. possible in reusable parts, because it restricts the number of configurations 
  11419. in which the reusable parts can be combined.
  11420.  
  11421. However, as more compilers begin to allow generics to be instantiated before 
  11422. the bodies are compiled, elaboration orders that generally follow compilation 
  11423. order may result in program errors.  By forcing the compiler to elaborate the 
  11424. generic before the instantiation, this error can be avoided or possibly 
  11425. identify a problem of circularity (see 10.5 of Department of Defense 1983).
  11426.  
  11427. Pragma Priority controls the priority of a task relative to all other tasks in
  11428. a particular system. It is inappropriate in a reusable part which does not
  11429. know anything about the requirements and importance of other parts of the
  11430. systems in which it is reused. Give careful consideration to a reusable part
  11431. which claims that it can only be reused if its embedded task has the highest
  11432. priority in the system. No two such parts can ever be used together.
  11433.  
  11434. note
  11435.  
  11436. It is not possible to parameterize tasks with a priority to be specified at 
  11437. instantiation or elaboration.  However, a library of reusable parts that 
  11438. contain tasks can be designed to depend on a single package of named numbers.  
  11439. These named numbers can then be easily updated to fit the application's need 
  11440. with the simple procedure of recompiling any library units that depend on the 
  11441. named numbers.  The configuration management implications of such an approach 
  11442. are heavily dependent on the Ada development environment and compilation 
  11443. system.
  11444.  
  11445. 8.4.3   Part Families
  11446.  
  11447. guideline
  11448.  
  11449. o       Create families of generic or other parts with similar specifications.
  11450.  
  11451. example
  11452.  
  11453. The Booch parts (Booch 1987) are an example of the application of this 
  11454. guideline.
  11455.  
  11456. rationale
  11457.  
  11458. Different versions of similar parts (e.g., bounded versus unbounded stacks)
  11459. may be needed for different applications or to change the properties of a
  11460. given application. Often, the different behaviors required by these versions
  11461. cannot be obtained using generic parameters. Providing a family of parts with
  11462. similar specifications makes it easy for the programmer to select the
  11463. appropriate one for the current application or to substitute a different one
  11464. if the needs of the application change.
  11465.  
  11466. note
  11467.  
  11468. A reusable part which is structured from subparts which are members of part 
  11469. families is particularly easy to tailor to the needs of a given application by 
  11470. substitution of family members.
  11471.  
  11472. 8.4.4   Conditional Compilation
  11473.  
  11474. guideline
  11475.  
  11476. o       Structure reusable code to take advantage of dead code removal by the 
  11477. compiler.
  11478.  
  11479. example
  11480.  
  11481. ------------------------------------------------------------------------
  11482. package Matrix_Math is
  11483.  
  11484.    ...
  11485.    type Algorithm is (Gaussian, Pivoting, Choleski, Tri_Diagonal);
  11486.  
  11487.    generic
  11488.       Which_Algorithm : in     Algorithm := Gaussian;
  11489.    procedure Invert ( ... );
  11490.  
  11491. end Matrix_Math;
  11492.  
  11493. ------------------------------------------------------------------------
  11494. package body Matrix_Math is
  11495.    ...
  11496.  
  11497.    ---------------------------------------------------------------------
  11498.    procedure Invert ( ... ) is
  11499.       ...
  11500.    begin  -- Invert
  11501.       case Which_Algorithm is
  11502.      when Gaussian =>     ... ;
  11503.      when Pivoting =>     ... ;
  11504.      when Choleski =>     ... ;
  11505.      when Tri_Diagonal => ... ;
  11506.       end case;
  11507.  
  11508.    end Invert;
  11509.    ---------------------------------------------------------------------
  11510.  
  11511. end Matrix_Math;
  11512. ------------------------------------------------------------------------
  11513.  
  11514. rationale
  11515.  
  11516. Some compilers omit object code corresponding to parts of the program which
  11517. they detect can never be executed. Constant expressions in conditional
  11518. statements take advantage of this feature where it is available, providing a
  11519. limited form of conditional compilation. When a part is reused in an
  11520. implementation that does not support this form of conditional compilation,
  11521. this practice produces a clean structure which is easy to adapt by deleting or
  11522. commenting out redundant code where it creates an unacceptable overhead.
  11523.  
  11524. This feature should be used when other factors prevent the code from being
  11525. separated into separate subunits.  In the above example, it would be
  11526. preferable to have a different procedure for each algorithm.  But the
  11527. algorithms may differ in slight but complex ways so as to make separate
  11528. procedures difficult to maintain.
  11529.  
  11530. caution
  11531.  
  11532. Be aware of whether your implementation supports dead code removal, and be 
  11533. prepared to take other steps to eliminate the overhead of redundant code if 
  11534. necessary.
  11535.  
  11536. 8.4.5   Table-Driven Programming
  11537.  
  11538. guideline
  11539.  
  11540. o       Write table-driven reusable parts where possible and appropriate.
  11541.  
  11542. example
  11543.  
  11544. The epitome of table-driven reusable software is a parser generation system. A
  11545. specification of the form of the input data and of its output, along with some 
  11546. specialization code, is converted to tables that are to be "walked" by
  11547. pre-existing code using predetermined algorithms in the parser produced. Other
  11548. forms of "application generators" work similarly.
  11549.  
  11550. rationale
  11551.  
  11552. Table-driven (sometimes known as data-driven) programs have behavior that
  11553. depends on data with'ed at compile time or read from a file at run-time. In
  11554. appropriate circumstances, table-driven programming provides a very powerful
  11555. way of creating general-purpose, easily tailorable, reusable parts.
  11556.  
  11557. note
  11558.  
  11559. Consider whether differences in the behavior of a general-purpose part could be
  11560. defined by some data structure at compile- or run-time and, if so, structure
  11561. the part to be table-driven. The approach is most likely to be applicable when
  11562. a part is designed for use in a particular application domain but needs to be 
  11563. specialized for use in a specific application within the domain. Take 
  11564. particular care in commenting the structure of the data needed to drive the 
  11565. part.
  11566.  
  11567. 8.5     SUMMARY
  11568.  
  11569. understanding and clarity
  11570.  
  11571. o       Select the least restrictive names possible for reusable parts and 
  11572. their identifiers.
  11573.  
  11574. o       Select the generic name to avoid conflicting with the naming 
  11575. conventions of instantiations of the generic.
  11576.  
  11577. o    Use names which indicate the behavioral characteristics of the
  11578. reusable part, as well as its abstraction.
  11579.  
  11580. o       Do not use any abbreviations in identifier or unit names.
  11581.  
  11582. o    Document the expected behavior of generic formal parameters just as
  11583. any package specification is documented.
  11584.  
  11585. robustness
  11586.  
  11587. o    Use named numbers and static expressions to allow multiple
  11588. dependencies to be linked to a small number of symbols.
  11589.  
  11590. o       Use unconstrained array types for array formal parameters and array 
  11591. return values.
  11592.  
  11593. o       Make the size of local variables depend on actual parameter size where 
  11594. appropriate.
  11595.  
  11596. o       Minimize the number of assumptions made by a unit.
  11597.  
  11598. o       For assumptions which cannot be avoided, use types to automatically 
  11599. enforce conformance.
  11600.  
  11601. o       For assumptions which cannot be automatically enforced by types, add 
  11602. explicit checks to the code.
  11603.  
  11604. o       Document all assumptions.
  11605.  
  11606. o       Beware of using subtypes as type marks when declaring generic formal 
  11607. objects of type in out.
  11608.  
  11609. o       Beware of using subtypes as type marks when declaring parameters or 
  11610. return values of generic formal subprograms.
  11611.  
  11612. o       Use attributes rather than literal values.
  11613.  
  11614. o       Be careful about overloading the names of subprograms exported by the 
  11615. same generic package.
  11616.  
  11617. o       Within a specification, document any tasks that would be activated by 
  11618. with'ing the specification and by using any part of the specification.
  11619.  
  11620. o       Document which generic formal parameters are accessed from a task 
  11621. hidden inside the generic unit.
  11622.  
  11623. o       Propagate exceptions out of reusable parts. Handle exceptions within 
  11624. reusable parts only when you are certain that the handling is appropriate in 
  11625. all circumstances.
  11626.  
  11627. o    Propagate exceptions raised by generic formal subprograms after
  11628. performing any cleanup necessary to the correct operation of future
  11629. invocations of the generic instantiation.
  11630.  
  11631. o       Leave state variables in a valid state when raising an exception.
  11632.  
  11633. o       Leave parameters unmodified when raising an exception.
  11634.  
  11635. adaptability
  11636.  
  11637. o       Provide complete functionality in a reusable part or set of parts. 
  11638. Build in complete functionality, including end conditions, even if some 
  11639. functionality is not needed in this application.
  11640.  
  11641. o       More specifically, provide initialization and finalization procedures 
  11642. for every data structure that may contain dynamic data.
  11643.  
  11644. o       Use generic units to avoid code duplication.
  11645.  
  11646. o       Parameterize generic units for maximum adaptability.
  11647.  
  11648. o       Reuse common instantiations of generic units, as well as the generic 
  11649. units themselves.
  11650.  
  11651. o       Use generic units to encapsulate algorithms independently of data type.
  11652.  
  11653. o       Use abstract data types in preference to abstract data objects.
  11654.  
  11655. o       Use generic units to implement abstract data types independently of 
  11656. their component data type.
  11657.  
  11658. o       Provide iterators for traversing complex data structures within 
  11659. reusable parts.
  11660.  
  11661. o       Provide both active and passive iterators.
  11662.  
  11663. o       Protect the iterators from errors due to modification of the data 
  11664. structure during iteration.
  11665.  
  11666. o       Document the behavior of the iterators when the data structure is 
  11667. modified during traversal.
  11668.  
  11669. o       Use limited private (not private) for generic formal types, explicitly 
  11670. importing assignment and equality operations if required.
  11671.  
  11672. o       Export the least restrictive type that maintains the integrity of the 
  11673. data and abstraction while allowing alternate implementations.
  11674.  
  11675. o       Use mode in out rather than out for parameters of a generic formal 
  11676. subprogram, when the parameters are of an imported limited type.
  11677.  
  11678. independence
  11679.  
  11680. o       Minimize with clauses on reusable parts, especially on their 
  11681. specifications.
  11682.  
  11683. o       Use generic parameters instead of with statements to reduce the number 
  11684. of context clauses on a reusable part.
  11685.  
  11686. o    Use generic parameters instead of with statements to import portions
  11687. of a package rather than the entire package.
  11688.  
  11689. o       For nongenerics named in a context clause, avoid pragma Elaborate.
  11690.  
  11691. o       Use a pragma Elaborate for generics named in a context clause.
  11692.  
  11693. o       Avoid pragma Priority in tasks hidden in reusable parts.
  11694.  
  11695. o       Create families of generic or other parts with similar specifications.
  11696.  
  11697. o       Structure reusable code to take advantage of dead code removal by the 
  11698. compiler.
  11699.  
  11700. o       Write table-driven reusable parts where possible and appropriate.
  11701.  
  11702.  
  11703.  
  11704.  
  11705. CHAPTER 9
  11706. Performance
  11707.  
  11708. In many ways, performance is at odds with maintainability and portability. To 
  11709. achieve improved speed or memory usage, the most clear algorithm sometimes 
  11710. gives way to confusing code. To exploit special purpose hardware or operating 
  11711. system services, nonportable implementation dependencies are introduced. When 
  11712. concerned about performance, you must decide how well each algorithm meets its 
  11713. performance and maintainability requirements.
  11714.  
  11715. Apply these guidelines after an application is working correctly. Don't become 
  11716. obsessed with improving performance when the application already meets its 
  11717. performance requirements. Modifying code to improve performance can introduce 
  11718. errors--so the benefits of tweaking an algorithm should be real and clearly 
  11719. outweigh the risk.
  11720.  
  11721. These guidelines should be applied after you know your compiler and target 
  11722. environment. Benchmarks and compiler generated assembly code can be evaluated 
  11723. to help instantiate these guidelines for your development environment.
  11724.  
  11725. 9.1     IMPROVING EXECUTION SPEED
  11726.  
  11727. 9.1.1   Pragma Inline
  11728.  
  11729. guideline
  11730.  
  11731. o    Use pragma Inline when calling overhead is a significant portion of
  11732. the routine's execution time.
  11733.  
  11734. example
  11735.  
  11736. procedure Assign (Variable : in out Integer;
  11737.           Value    : in     Integer);
  11738. pragma Inline (Assign);
  11739.  
  11740. ...
  11741. procedure Assign (Variable : in out Integer;
  11742.           Value    : in     Integer) is
  11743. begin
  11744.    Variable := Value;
  11745. end Assign;
  11746.  
  11747. rationale
  11748.  
  11749. Procedure and function invocations include overhead that is unnecessary when
  11750. the code involved is very small.  These small routines are usually written to
  11751. maintain the implementation hiding characteristics of a package.  They may
  11752. also simply pass their parameters unchanged to another routine.  When one of
  11753. these routines appears in some code that needs to run faster, either the
  11754. implementation hiding principle needs to be violated or a pragma Inline can be
  11755. introduced.
  11756.  
  11757. The use of pragma Inline does have its disadvantages.  It can create 
  11758. compilation dependencies on the body; i.e., when the specification uses a 
  11759. pragma Inline, both the specification and corresponding body may need to be 
  11760. compiled before the specification can be used.  As updates are made to the 
  11761. code, a routine may become more complex (larger) and the continued use of a 
  11762. pragma Inline may no longer be justified.
  11763.  
  11764. exception
  11765.  
  11766. Although it is rare, Inlining code may increase code size which can lead to 
  11767. slower performance caused by additional paging.  A pragma Inline may actually 
  11768. thwart a compiler's attempt to use some other optimization technique such as 
  11769. register optimization.
  11770.  
  11771. When a compiler is already doing a good job of selecting routines to be 
  11772. inlined, the pragma may accomplish little, if any, improvement in execution 
  11773. speed.
  11774.  
  11775. 9.1.2   Blocks
  11776.  
  11777. guideline
  11778.  
  11779. o       Use blocks to introduce late initialization (Guideline 5.6.9).
  11780.  
  11781. o       Remove blocks that introduce overhead.
  11782.  
  11783. example
  11784.  
  11785.    ...
  11786.    Initial : Matrix;
  11787.  
  11788. begin  -- Find_Solution
  11789.  
  11790.    Initialize_Solution_Matrix:
  11791.       for Row in Initial'Range(1) loop
  11792.      for Col in Initial'Range(2) loop
  11793.         Initial(Row, Col) := Get_Value(Row, Col);
  11794.      end loop;
  11795.       end loop Initialize_Solution_Matrix;
  11796.  
  11797.    Converge_To_The_Solution:
  11798.       declare
  11799.  
  11800.      Solution       : Matrix           := Identity;
  11801.      Min_Iterations : constant Natural := ...;
  11802.  
  11803.       begin  -- Converge_To_The_Solution
  11804.      for Iterations in 1 .. Min_Iterations loop
  11805.         Converge(Solution, Initial);
  11806.      end loop;
  11807.  
  11808.       end Converge_To_The_Solution;
  11809.  
  11810.    ...
  11811. end Find_Solution;
  11812.  
  11813. rationale
  11814.  
  11815. Late initialization allows a compiler more choices in register usage 
  11816. optimization.  Depending on the circumstance, this may introduce a significant 
  11817. performance improvement.
  11818.  
  11819. Some compilers incur a performance penalty when declarative blocks are 
  11820. introduced.  Careful analysis and timing tests by the programmer may identify 
  11821. those declarative blocks that should be removed.
  11822.  
  11823. note
  11824.  
  11825. It is difficult to accurately predict through code inspections which
  11826. declarative blocks improve performance and which degrade performance.
  11827. However, with these general guidelines and a familiarity with the particular
  11828. implementation, performance can be improved.
  11829.  
  11830. 9.1.3   Arrays
  11831.  
  11832. guideline
  11833.  
  11834. o       Use constrained arrays.
  11835.  
  11836. o       Use zero based indexing for arrays.
  11837.  
  11838. example
  11839.  
  11840. -- M, N are variables which change value at runtime.
  11841. type Unconstrained       is array (Integer range M .. N)     of Element;
  11842. type Zero_Based          is array (Integer range 0 .. N - M) of Element;
  11843. type Constrained_0_Based is array (Integer range 0 .. 9)     of Element;
  11844.  
  11845. rationale
  11846.  
  11847. Unconstrained arrays often leave address and offset calculations until
  11848. runtime.  Constrained arrays can be optimized by performing some calculations
  11849. once at compile time.  A detailed discussion of the tradeoffs and alternatives
  11850. can be found in NASA (1992).
  11851.  
  11852. Although zero based indexing is not as intuitive for humans, it simplifies
  11853. many of the necessary calculations for indexing into arrays.
  11854.  
  11855. note
  11856.  
  11857. Generic utilities for handling arrays can be instantiated on constrained or 
  11858. unconstrained arrays with arbitrary indexes.  Then the compiler can optimize 
  11859. the utility when the more efficient structure is used (assuming the generic is 
  11860. not sharing code!).  Again, further details can be found in NASA (1992).
  11861.  
  11862. 9.1.4   Mod and Rem Operators
  11863.  
  11864. guideline
  11865.  
  11866. o       Use incremental schemes instead of the mod and rem operators when 
  11867. possible.
  11868.  
  11869. example
  11870.  
  11871. The following is slow:
  11872.  
  11873. for I in 0 .. N loop
  11874.    Update(Arr(I mod Modulator));
  11875. end loop;
  11876.  
  11877. The following is equivalent, and avoids the mod operator:
  11878.  
  11879. J := 0;
  11880. for I in 0 .. N loop
  11881.    Update(Arr(J));
  11882.  
  11883.    if J = Modulator then
  11884.       J := 0;
  11885.    else  -- j < Modulator
  11886.       J := J + 1;
  11887.    end if;
  11888. end loop;
  11889.  
  11890. rationale
  11891.  
  11892. The mod and rem operators are very convenient, but relatively slow.  In 
  11893. isolated cases where performance is of concern, a straightforward mapping to 
  11894. incremental schemes is possible.
  11895.  
  11896. note
  11897.  
  11898. Most of the incremental schemes that avoid the mod and rem operations are
  11899. prime candidates for generic utilities.  Programmers may then conveniently
  11900. apply this optimization when needed.
  11901.  
  11902. 9.1.5   Constraint Checking
  11903.  
  11904. guideline
  11905.  
  11906. o    Use strong typing with carefully selected constraints to reduce
  11907. runtime constraint checking.
  11908.  
  11909. example
  11910.  
  11911. In this example, two potential constraint checks are eliminated:  If the 
  11912. function, Get_Response, returns String, then the initialization of the 
  11913. variable, Input, would require constraint checking.  If the variable, Last, is 
  11914. type Positive, then the assignment inside the loop would require constraint 
  11915. checking.
  11916.  
  11917.    ...
  11918.    subtype Name_Index is Positive range 1 .. 32;
  11919.    subtype Name       is String (Name_Index);
  11920.    ...
  11921.    function Get_Response return Name is separate;
  11922.    ...
  11923. begin
  11924.       ...
  11925.    Find_Last_Period:
  11926.    declare
  11927.       -- No Constraint Checking needed for initialization
  11928.       Input       : constant Name       := Get_Response;
  11929.       Last_Period :          Name_Index := 1;
  11930.  
  11931.    begin  -- Find_Last_Period
  11932.       for I in Input'Range loop
  11933.      if Input(I) = '.' then
  11934.         -- No Constraint Checking needed in  this `tight' loop
  11935.         Last_Period := I;
  11936.      end if;
  11937.  
  11938.       end loop;
  11939.       ...
  11940.  
  11941. rationale
  11942.  
  11943. Since runtime constraint checking is associated with slow performance, it is
  11944. not intuitive that the addition of constrained types could actually improve
  11945. performance.  However, the need for constraint checking appears in many places
  11946. regardless of the use of constrained subtypes.  Even assignments to variables
  11947. that use the predefined types may need constraint checks.  By consistently
  11948. using constrained types, many of the unnecessary runtime checking can be
  11949. eliminated.  Instead, the checking is usually moved to less frequently
  11950. executed code involved in system input.  In the example, the function,
  11951. Get_Response, may need to check the length of a user supplied string and raise
  11952. an exception.
  11953.  
  11954. Some compilers can do additional optimizations based on the information 
  11955. provided by constrained types.  For example, although an unconstrained array 
  11956. does not have a fixed size, it has a maximum size which can be determined from 
  11957. the range of its index.  Performance can be improved by limiting this maximum 
  11958. size to a "reasonable" number.  Refer to the discussion on unconstrained arrays
  11959. found in NASA (1992).
  11960.  
  11961. 9.2     SUMMARY
  11962.  
  11963. improving execution speed
  11964.  
  11965. o    Use pragma Inline when calling overhead is a significant portion of
  11966. the routine's execution time.
  11967.  
  11968. o       Use blocks to introduce late initialization (Guideline 5.6.9).
  11969.  
  11970. o       Remove blocks that introduce overhead.
  11971.  
  11972. o       Use constrained arrays.
  11973.  
  11974. o       Use zero based indexing for arrays.
  11975.  
  11976. o       Use incremental schemes instead of the mod and rem operators when 
  11977. possible.
  11978.  
  11979. o    Use strong typing with carefully selected constraints to reduce
  11980. runtime constraint checking.
  11981.  
  11982.  
  11983.  
  11984.  
  11985. CHAPTER 10
  11986. Complete Examples
  11987.  
  11988. This chapter contains example programs illustrating the use of 
  11989. guidelines.  Since many of the guidelines leave the program writer to decide 
  11990. what is best, there is no single best or correct example of how to use Ada.  
  11991. Instead, you will find several styles that differ from your own that may 
  11992. deserve consideration.
  11993.  
  11994. There are some guidelines that rarely have exceptions and leave little room
  11995. for choice.  When you find that these examples do not reflect the way you
  11996. normally code, investigate why by finding the guideline that was followed and
  11997. study the rationale.  This practical exercise should be helpful in identifying
  11998. potential areas of improvement (whether for you or this style guide!).
  11999.  
  12000. The Menu-Driven User Interface example provides a short example demonstrating 
  12001. many of the guidelines.  It also provides the basic types for later examples.
  12002.  
  12003. The two versions of the Dining Philosophers example program demonstrate the 
  12004. portability of Ada packages and tasking.  They were provided by Dr. Michael B. 
  12005. Feldman.  Most of the available compilers can successfully compile these 
  12006. examples.  They have also been successfully tested on a variety of platforms.
  12007.  
  12008. 10.1  MENU-DRIVEN USER INTERFACE
  12009.  
  12010. The program implements a simple menu-driven user interface that can be used as 
  12011. the front end for a variety of applications.  It consists of a package for 
  12012. locally defined types; SPC_Numeric_Types; instantiations of Input/Output 
  12013. packages for those types; a package to perform ASCII terminal I/O for 
  12014. generating menus, writing prompts, and receiving user input; Terminal_IO; and 
  12015. finally an example using the terminal I/O routines; Example.
  12016.  
  12017. Within Terminal_IO, subprogram names are overloaded when several subprograms 
  12018. perform the same general function but for different data types.
  12019.  
  12020. The body for Terminal_IO uses separate compilation capabilities for a
  12021. subprogram, Display_Menu, that is larger and more involved than the rest.
  12022. Note, all literals that would be required are defined as constants. Nested
  12023. loops, where they exist, are also named. The numeric "get" functions defined
  12024. in the body of package, Terminal_IO, encapsulate exception handlers within a
  12025. loop.  Where locally defined types could not be used, there is a comment
  12026. explaining the reason. The use of short circuit control forms, both on an if
  12027. and an exit statement, are also illustrated.
  12028.  
  12029. The information that would have been in the file headers is redundant since it 
  12030. is contained in the title page of this book. The file headers are omitted from 
  12031. the following listings:
  12032.  
  12033. ------------------------------------------------------------------------
  12034.  
  12035. package SPC_Numeric_Types is
  12036.  
  12037.    type Tiny_Integer   is range -2** 7 .. 2** 7 - 1;
  12038.    type Medium_Integer is range -2**15 .. 2**15 - 1;
  12039.    type Big_Integer    is range -2**31 .. 2**31 - 1;
  12040.  
  12041.    subtype Tiny_Natural   is
  12042.               Tiny_Integer   range 0 ..   Tiny_Integer'Last;
  12043.    subtype Medium_Natural is
  12044.               Medium_Integer range 0 .. Medium_Integer'Last;
  12045.    subtype Big_Natural    is
  12046.               Big_Integer    range 0 ..    Big_Integer'Last;
  12047.  
  12048.    subtype Tiny_Positive   is
  12049.               Tiny_Integer   range 1 ..   Tiny_Integer'Last;
  12050.    subtype Medium_Positive is
  12051.               Medium_Integer range 1 .. Medium_Integer'Last;
  12052.    subtype Big_Positive    is
  12053.               Big_Integer    range 1 ..    Big_Integer'Last;
  12054.  
  12055.    type Medium_Float is digits 6;
  12056.    type Big_Float    is digits 9;
  12057.  
  12058.    subtype Probabilities is Medium_Float range 0.0 .. 1.0;
  12059.  
  12060.    function Min (Left  : in     Tiny_Integer;
  12061.          Right : in     Tiny_Integer)
  12062.      return Tiny_Integer;
  12063.  
  12064.    function Max (Left  : in     Tiny_Integer;
  12065.          Right : in     Tiny_Integer)
  12066.      return Tiny_Integer;
  12067.  
  12068.    -- Additional function declarations to return the minimum and maximum
  12069.    --|   values for each type.
  12070.  
  12071. end SPC_Numeric_Types;
  12072.  
  12073. ------------------------------------------------------------------------
  12074.  
  12075. package body SPC_Numeric_Types is
  12076.  
  12077.    ---------------------------------------------------------------------
  12078.  
  12079.    function Min (Left  : in     Tiny_Integer;
  12080.          Right : in     Tiny_Integer)
  12081.      return Tiny_Integer is
  12082.    begin
  12083.  
  12084.       if Left < Right then
  12085.      return Left;
  12086.       else -- Left >= Right
  12087.      return Right;
  12088.       end if;
  12089.  
  12090.    end Min;
  12091.  
  12092.    ---------------------------------------------------------------------
  12093.  
  12094.    function Max (Left  : in     Tiny_Integer;
  12095.          Right : in     Tiny_Integer)
  12096.      return Tiny_Integer is
  12097.    begin
  12098.  
  12099.       if Left > Right then
  12100.      return Left;
  12101.       else -- Left <= Right
  12102.      return Right;
  12103.       end if;
  12104.  
  12105.    end Max;
  12106.  
  12107.    ---------------------------------------------------------------------
  12108.  
  12109.    -- Additional functions to return minimum and maximum value for each
  12110.    --|   type defined in the package.
  12111.  
  12112. end SPC_Numeric_Types;
  12113.  
  12114. ------------------------------------------------------------------------
  12115.  
  12116. with SPC_Numeric_Types;
  12117. with Text_IO;
  12118. package SPC_Small_Integer_IO is
  12119.       new Text_IO.Integer_IO (SPC_Numeric_Types.Tiny_Integer);
  12120.  
  12121. with SPC_Numeric_Types;
  12122. with Text_IO;
  12123. package Medium_Integer_IO is
  12124.       new Text_IO.Integer_IO (SPC_Numeric_Types.Medium_Integer);
  12125.  
  12126. with SPC_Numeric_Types;
  12127. with Text_IO;
  12128. package Big_Integer_IO is
  12129.       new Text_IO.Integer_IO (SPC_Numeric_Types.Big_Integer);
  12130.  
  12131. with SPC_Numeric_Types;
  12132. with Text_IO;
  12133. package Medium_Float_IO is
  12134.       new Text_IO.Float_IO   (SPC_Numeric_Types.Medium_Float);
  12135.  
  12136. with SPC_Numeric_Types;
  12137. with Text_IO;
  12138. package Big_Float_IO is
  12139.       new Text_IO.Float_IO   (SPC_Numeric_Types.Big_Float);
  12140.  
  12141. ------------------------------------------------------------------------
  12142.  
  12143. with SPC_Numeric_Types;
  12144. use  SPC_Numeric_Types;
  12145.  
  12146. package Terminal_IO is
  12147.  
  12148.    Max_File_Name_Length : constant := 30;
  12149.    Max_Line             : constant := 30;
  12150.  
  12151.    subtype Alpha_Numeric is Character range '0' .. 'Z';
  12152.    subtype Line          is String (1 .. Max_Line);
  12153.  
  12154.    Empty_Line : constant Line := (others => ' ');
  12155.  
  12156.    type Menu is array (Alpha_Numeric) of Line;
  12157.  
  12158.    subtype File_Name is String (1 .. Max_File_Name_Length);
  12159.  
  12160.    procedure Get_File_Name (Prompt      : in     String;
  12161.                 Name        :    out File_Name;
  12162.                 Name_Length :    out Natural);
  12163.  
  12164.    function Yes (Prompt : in     String) return Boolean;
  12165.    function Get (Prompt : in     String) return Medium_Integer;
  12166.    function Get (Prompt : in     String) return Medium_Float;
  12167.  
  12168.    procedure Display_Menu (Title   : in     String;
  12169.                Options : in     Menu;
  12170.                Choice  :    out Alpha_Numeric);
  12171.  
  12172.    procedure Pause (Prompt : in     String);
  12173.    procedure Pause;
  12174.  
  12175.    procedure Put (Integer_Value : in     Medium_Integer);
  12176.    procedure Put (Real_Value    : in     Medium_Float);
  12177.    procedure Put (Label         : in     String;
  12178.           Integer_Value : in     Medium_Integer);
  12179.    procedure Put (Label         : in     String;
  12180.           Real_Value    : in     Medium_Float);
  12181.  
  12182.    procedure Put_Line (Integer_Value : in     Medium_Integer);
  12183.    procedure Put_Line (Real_Value    : in     Medium_Float);
  12184.    procedure Put_Line (Label         : in     String;
  12185.                Integer_Value : in     Medium_Integer);
  12186.    procedure Put_Line (Label         : in     String;
  12187.                Real_Value    : in     Medium_Float);
  12188.  
  12189. end Terminal_IO;
  12190.  
  12191. ------------------------------------------------------------------------
  12192.  
  12193. with Medium_Integer_IO;
  12194. with Medium_Float_IO;
  12195. with Text_IO;
  12196.  
  12197. package body Terminal_IO is
  12198.  
  12199.    -- simple terminal i/o routines
  12200.    subtype Response is String (1 .. 20);
  12201.  
  12202.    Prompt_Column   : constant           := 30;
  12203.    Question_Mark   : constant String    := " ? ";
  12204.    Standard_Prompt : constant String    := " ==> ";
  12205.    Blank           : constant Character := ' ';
  12206.  
  12207.    Real_Fore     : constant := 4;
  12208.    Real_Aft      : constant := 3;
  12209.    Integer_Width : constant := 4;
  12210.  
  12211.    ---------------------------------------------------------------------
  12212.  
  12213.    procedure Put_Prompt (Prompt   : in     String;
  12214.              Question : in     Boolean := False) is
  12215.       use Text_IO;
  12216.    begin
  12217.       Put(Prompt);
  12218.       if Question then
  12219.      Put(Question_Mark);
  12220.       end if;
  12221.  
  12222.       Set_Col(Prompt_Column);
  12223.       Put(Standard_Prompt);
  12224.    end Put_Prompt;
  12225.  
  12226.    ---------------------------------------------------------------------
  12227.  
  12228.    function Yes (Prompt : in     String) return Boolean is
  12229.  
  12230.       Response_String : Response := (others => Blank);
  12231.       Response_String_Length : Natural;
  12232.  
  12233.    begin  -- Yes
  12234.       Get_Response:
  12235.  
  12236.      loop
  12237.         Put_Prompt(Prompt, Question => True);
  12238.         Text_IO.Get_Line(Response_String, Response_String_Length);
  12239.  
  12240.         Find_First_Non_Blank_Character:
  12241.            for Position in 1 .. Response_String_Length loop
  12242.  
  12243.           if Response_String(Position) /= Blank then
  12244.  
  12245.              return Response_String(Position) = 'Y' or
  12246.                Response_String(Position) = 'y';
  12247.  
  12248.           end if;
  12249.  
  12250.            end loop Find_First_Non_Blank_Character;
  12251.  
  12252.         -- issue prompt until non-blank responses
  12253.         Text_IO.New_Line;
  12254.      end loop Get_Response;
  12255.    end Yes;
  12256.  
  12257.    ---------------------------------------------------------------------
  12258.  
  12259.    procedure Get_File_Name (Prompt      : in     String;
  12260.                 Name        :    out File_Name;
  12261.                 Name_Length :    out Natural) is
  12262.    begin
  12263.       Put_Prompt(Prompt);
  12264.       Text_IO.Get_Line(Name, Name_Length);
  12265.    end Get_File_Name;
  12266.  
  12267.    ---------------------------------------------------------------------
  12268.  
  12269.    function Get (Prompt : in     String) return Medium_Integer is
  12270.  
  12271.       Response_String : Response := (others => Blank);
  12272.       Last            : Natural;               -- Required by Get_Line.
  12273.       Value           : Medium_Integer;
  12274.  
  12275.    begin  -- Get
  12276.       loop
  12277.  
  12278.      Catch_Input_Errors:
  12279.         begin
  12280.            Put_Prompt(Prompt);
  12281.            Text_IO.Get_Line(Response_String, Last);
  12282.            Value :=
  12283.              Medium_Integer'Value(Response_String(1 .. Last));
  12284.  
  12285.            return Value;
  12286.  
  12287.         exception
  12288.            when others =>
  12289.           Text_IO.Put_Line("Please enter an integer");
  12290.         end Catch_Input_Errors;
  12291.  
  12292.       end loop;
  12293.    end Get;
  12294.  
  12295.    ---------------------------------------------------------------------
  12296.  
  12297.    procedure Display_Menu (Title   : in     String;
  12298.                Options : in     Menu;
  12299.                Choice  :    out Alpha_Numeric) is separate;
  12300.  
  12301.    ---------------------------------------------------------------------
  12302.  
  12303.    procedure Pause (Prompt : in     String) is
  12304.    begin
  12305.       Text_IO.Put_Line(Prompt);
  12306.       Pause;
  12307.    end Pause;
  12308.  
  12309.    ---------------------------------------------------------------------
  12310.  
  12311.    procedure Pause is
  12312.  
  12313.       Buffer : Response;
  12314.       Last : Natural;
  12315.  
  12316.    begin  -- Pause
  12317.       Text_IO.Put("Press return to continue");
  12318.       Text_IO.Get_Line(Buffer, Last);
  12319.    end Pause;
  12320.  
  12321.    ---------------------------------------------------------------------
  12322.  
  12323.    function Get (Prompt : in     String) return Medium_Float is
  12324.  
  12325.       Value : Medium_Float;
  12326.  
  12327.    begin  -- Get
  12328.       loop
  12329.  
  12330.      Catch_Input_Errors:
  12331.         begin
  12332.            Put_Prompt(Prompt);
  12333.            Medium_Float_IO.Get(Value);
  12334.            Text_IO.Skip_Line;
  12335.  
  12336.            return Value;
  12337.  
  12338.         exception
  12339.            when others =>
  12340.           Text_IO.Skip_Line;
  12341.           Text_IO.Put_Line("Please enter a real number");
  12342.         end Catch_Input_Errors;
  12343.  
  12344.       end loop;
  12345.    end Get;
  12346.  
  12347.    ---------------------------------------------------------------------
  12348.  
  12349.    procedure Put (Integer_Value : in     Medium_Integer) is
  12350.    begin
  12351.       Medium_Integer_IO.Put(Integer_Value, Width => Integer_Width);
  12352.    end Put;
  12353.  
  12354.    ---------------------------------------------------------------------
  12355.  
  12356.    procedure Put (Real_Value : in     Medium_Float) is
  12357.    begin
  12358.       Medium_Float_IO.Put
  12359.            (Real_Value,
  12360.         Fore => Real_Fore,
  12361.         Aft  => Real_Aft,
  12362.         Exp  => 0);
  12363.    end Put;
  12364.  
  12365.    ---------------------------------------------------------------------
  12366.  
  12367.    procedure Put (Label         : in     String;
  12368.           Integer_Value : in     Medium_Integer) is
  12369.    begin
  12370.       Text_IO.Put(Label);
  12371.       Medium_Integer_IO.Put(Integer_Value);
  12372.    end Put;
  12373.  
  12374.    ---------------------------------------------------------------------
  12375.  
  12376.    procedure Put (Label      : in     String;
  12377.           Real_Value : in     Medium_Float) is
  12378.    begin
  12379.       Text_IO.Put(Label);
  12380.       Medium_Float_IO.Put
  12381.            (Real_Value,
  12382.         Fore => Real_Fore,
  12383.         Aft  => Real_Aft,
  12384.         Exp  => 0);
  12385.    end Put;
  12386.  
  12387.    ---------------------------------------------------------------------
  12388.  
  12389.    procedure Put_Line (Integer_Value : in     Medium_Integer) is
  12390.    begin
  12391.       Terminal_IO.Put(Integer_Value);
  12392.       Text_IO.New_Line;
  12393.    end Put_Line;
  12394.  
  12395.    ---------------------------------------------------------------------
  12396.  
  12397.    procedure Put_Line (Real_Value : in     Medium_Float) is
  12398.    begin
  12399.       Terminal_IO.Put(Real_Value);
  12400.       Text_IO.New_Line;
  12401.    end Put_Line;
  12402.  
  12403.    ---------------------------------------------------------------------
  12404.  
  12405.    procedure Put_Line (Label         : in     String;
  12406.                Integer_Value : in     Medium_Integer) is
  12407.    begin
  12408.       Terminal_IO.Put(Label, Integer_Value);
  12409.       Text_IO.New_Line;
  12410.    end Put_Line;
  12411.  
  12412.    ---------------------------------------------------------------------
  12413.  
  12414.    procedure Put_Line (Label      : in     String;
  12415.                Real_Value : in     Medium_Float) is
  12416.    begin
  12417.       Terminal_IO.Put(Label, Real_Value);
  12418.       Text_IO.New_Line;
  12419.    end Put_Line;
  12420.  
  12421.    ---------------------------------------------------------------------
  12422.  
  12423. end Terminal_IO;
  12424.  
  12425. ------------------------------------------------------------------------
  12426.  
  12427. separate (Terminal_IO)
  12428. procedure Display_Menu (Title   : in     String;
  12429.             Options : in     Menu;
  12430.             Choice  :    out Alpha_Numeric) is
  12431.  
  12432.    Left_Column  : constant := 15;
  12433.    Right_Column : constant := 20;
  12434.  
  12435.    type Alpha_Array is array (Alpha_Numeric) of Boolean;
  12436.  
  12437.    Valid        : Boolean;
  12438.    Valid_Option : Alpha_Array := (others => False);
  12439.  
  12440.    ---------------------------------------------------------------------
  12441.  
  12442.    procedure Draw_Menu (Title   : in     String;
  12443.             Options : in     Menu) is
  12444.  
  12445.       use Text_IO;
  12446.  
  12447.    begin
  12448.       New_Page;
  12449.       New_Line;
  12450.       Set_Col(Right_Column);
  12451.       Put_Line(Title);
  12452.       New_Line;
  12453.  
  12454.       for Choice in Alpha_Numeric loop
  12455.  
  12456.      if Options(Choice) /= Empty_Line then
  12457.         Valid_Option(Choice) := True;
  12458.         Set_Col(Left_Column);
  12459.         Put(Choice & " -- ");
  12460.         Put_Line(Options(Choice));
  12461.      end if;
  12462.  
  12463.       end loop;
  12464.    end Draw_Menu;
  12465.  
  12466.    ---------------------------------------------------------------------
  12467.  
  12468.    procedure Get_Response (Valid  :    out Boolean;
  12469.                Choice :    out Alpha_Numeric) is
  12470.  
  12471.       Buffer_Size : constant               := 20;
  12472.       Dummy       : constant Alpha_Numeric := 'X';
  12473.  
  12474.       First_Char : Character;
  12475.       Buffer     : String (1 .. Buffer_Size);
  12476.  
  12477.       -- IMPLEMENTATION NOTE:
  12478.       -- The following two declarations do not use locally defined types
  12479.       --|   because a variable of type Natural is required by the
  12480.       --|   Text_IO routines for strings, and there is no relational
  12481.       --|   operator defined for our local Tiny_, Medium_, or
  12482.       --|   Big_Positive and the standard type Natural.
  12483.       Last  : Natural;
  12484.       Index : Positive;
  12485.  
  12486.       ------------------------------------------------------------------
  12487.  
  12488.       function Upper_Case (Current_Char : in     Character)
  12489.           return Character is
  12490.  
  12491.      Case_Difference : constant
  12492.              := Character'Pos('a') - Character'Pos('A');
  12493.  
  12494.       begin  -- Upper_Case
  12495.  
  12496.      if Current_Char in 'a' .. 'z' then
  12497.         return
  12498.           Character'Val
  12499.         (Character'Pos(Current_Char) - Case_Difference);
  12500.  
  12501.      else -- Current_Char not in 'a' .. 'z'
  12502.         return Current_Char;
  12503.      end if;
  12504.  
  12505.       end Upper_Case;
  12506.  
  12507.       ------------------------------------------------------------------
  12508.  
  12509.       use Text_IO;
  12510.    begin  -- Get_Response
  12511.  
  12512.       New_Line;
  12513.       Set_Col(Left_Column);
  12514.       Put(Standard_Prompt);
  12515.  
  12516.       Get_Line(Buffer, Last);
  12517.  
  12518.       Index := Buffer'First;
  12519.       for Position in Buffer'First .. Last loop
  12520.      Index := Position;
  12521.      exit when Upper_Case(Buffer(Index)) in Alpha_Numeric;
  12522.       end loop;
  12523.  
  12524.       First_Char := Upper_Case(Buffer(Index));
  12525.  
  12526.       if First_Char in Alpha_Numeric and then
  12527.      Valid_Option(First_Char) then
  12528.      Valid  := True;
  12529.      Choice := First_Char;
  12530.  
  12531.       else -- not a valid character
  12532.      Valid  := False;
  12533.      Choice := Dummy;
  12534.       end if;
  12535.  
  12536.    end Get_Response;
  12537.  
  12538.    ---------------------------------------------------------------------
  12539.  
  12540.    procedure Beep is
  12541.    begin
  12542.       Text_IO.Put(ASCII.Bel);
  12543.    end Beep;
  12544.  
  12545.    ---------------------------------------------------------------------
  12546.  
  12547. begin  -- Display_Menu
  12548.    loop
  12549.       Draw_Menu(Title, Options);
  12550.       Get_Response(Valid, Choice);
  12551.       exit when Valid;
  12552.       Beep;
  12553.    end loop;
  12554. end Display_Menu;
  12555.  
  12556. ------------------------------------------------------------------------
  12557.  
  12558. with SPC_Numeric_Types;
  12559. with Terminal_IO;
  12560.  
  12561. procedure Example is
  12562.  
  12563.    package TIO renames Terminal_IO;
  12564.  
  12565.    Example_Menu : constant TIO.Menu := TIO.Menu'
  12566.           ('A'    => "Add item                      ",
  12567.            'D'    => "Delete item                   ",
  12568.            'M'    => "Modify item                   ",
  12569.            'Q'    => "Quit                          ",
  12570.            others => TIO.Empty_Line);
  12571.  
  12572.    User_Choice : TIO.Alpha_Numeric;
  12573.    Item        : SPC_Numeric_Types.Medium_Integer;
  12574.  
  12575. begin  -- Example
  12576.  
  12577.    loop
  12578.       TIO.Display_Menu("Example Menu", Example_Menu, User_Choice);
  12579.  
  12580.       case User_Choice is
  12581.      when 'A'    =>    Item := TIO.Get ("Item to add");
  12582.      when 'D'    =>    Item := TIO.Get ("Item to delete");
  12583.      when 'M'    =>    Item := TIO.Get ("Item to modify");
  12584.      when 'Q'    =>    exit;
  12585.  
  12586.      when others => -- error has already been signaled to user
  12587.         null;
  12588.       end case;
  12589.  
  12590.    end loop;
  12591.  
  12592. end Example;
  12593.  
  12594. ------------------------------------------------------------------------
  12595. --  This is what is displayed, anything but A, D, M or Q beeps
  12596. --
  12597. --                 Example Menu
  12598. --
  12599. --            A -- Add item
  12600. --            D -- Delete item
  12601. --            M -- Modify item
  12602. --            Q -- Quit
  12603. --
  12604. --             ==>
  12605.  
  12606. 10.2    LINE-ORIENTED PORTABLE DINING PHILOSOPHERS EXAMPLE
  12607.  
  12608. Michael B. Feldman
  12609. Dept. of Electrical Engineering and Computer Science
  12610. The George Washington University
  12611. Washington, DC 20052
  12612.  
  12613. (202) 994-5253
  12614. mfeldman@seas.gwu.edu
  12615.  
  12616. Copyright 1991, Michael B. Feldman
  12617.  
  12618. These programs may be freely copied, distributed, and modified for educational
  12619. purposes but not for profit.  If you modify or enhance the program (for
  12620. example, to use other display systems), please send Dr. Feldman a copy of the
  12621. modified code, either on diskette or by e-mail.
  12622.  
  12623. This system is an elaborate implementation of Edsger Dijkstra's famous Dining 
  12624. Philosophers; a classical demonstration of deadlock problems in concurrent 
  12625. programming.
  12626.  
  12627. This example uses the numeric types from the Menu-Driven User Interface  
  12628. example. At least one compiler (Ada/Ed) does not support floating-point 
  12629. precision greater than 6 digits.  In this case, Big_Float will need a smaller 
  12630. precision (digits 6 for Ada/Ed).
  12631.  
  12632. ------------------------------------------------------------------------
  12633.  
  12634. with SPC_Numeric_Types;
  12635. use  SPC_Numeric_Types;
  12636. package Random is
  12637.  
  12638.    -- Simple pseudo-random number generator package.
  12639.    -- Adapted from the Ada literature by
  12640.    -- Michael B. Feldman, The George Washington University,
  12641.    -- November 1990.
  12642.  
  12643.    procedure Set_Seed (N : in     Medium_Positive);
  12644.  
  12645.    function Unit_Random return Medium_Float;
  12646.  
  12647.    --returns a float >=0.0 and <1.0
  12648.  
  12649.    function Random_Int (N : in     Medium_Positive)
  12650.      return Medium_Positive;
  12651.  
  12652.    --return a random integer in the range 1..N
  12653.  
  12654. end Random;
  12655.  
  12656. ------------------------------------------------------------------------
  12657.  
  12658. package Chop is
  12659.  
  12660.    task type Stick is
  12661.  
  12662.       entry Pick_Up;
  12663.       entry Put_Down;
  12664.  
  12665.    end Stick;
  12666.  
  12667. end Chop;
  12668.  
  12669. ------------------------------------------------------------------------
  12670.  
  12671. with SPC_Numeric_Types;
  12672. use  SPC_Numeric_Types;
  12673. package Phil is
  12674.  
  12675.    task type Philosopher is
  12676.  
  12677.       entry Come_To_Life (My_ID      : in     Medium_Natural;
  12678.               Chopstick1 : in     Medium_Natural;
  12679.               Chopstick2 : in     Medium_Natural);
  12680.  
  12681.    end Philosopher;
  12682.  
  12683.    type States is
  12684.      (Breathing,       Thinking,        Eating,        Done_Eating,
  12685.       Got_One_Stick,   Got_Other_Stick);
  12686.  
  12687. end Phil;
  12688.  
  12689. ------------------------------------------------------------------------
  12690.  
  12691. with SPC_Numeric_Types;
  12692. use  SPC_Numeric_Types;
  12693. with Chop;
  12694. with Phil;
  12695.  
  12696. package Room is
  12697.  
  12698.    Table_Size : constant := 5;
  12699.    subtype Table_Type is Medium_Natural range 1 .. Table_Size;
  12700.  
  12701.    Sticks : array (Table_Type) of Chop.Stick;
  12702.  
  12703.    task Head_Waiter is
  12704.  
  12705.       entry Open_The_Room;
  12706.       entry Report_State (Which_Phil : in     Table_Type;
  12707.               State      : in     Phil.States;
  12708.               How_Long   : in     Medium_Natural := 0);
  12709.  
  12710.    end Head_Waiter;
  12711.  
  12712. end Room;
  12713.  
  12714. ------------------------------------------------------------------------
  12715.  
  12716. with Room;
  12717. procedure Diners is
  12718. begin
  12719.    Room.Head_Waiter.Open_The_Room;
  12720.  
  12721.    loop
  12722.       delay 20.0;
  12723.    end loop;
  12724. end Diners;
  12725.  
  12726. ------------------------------------------------------------------------
  12727.  
  12728. with Calendar;
  12729. with SPC_Numeric_Types;
  12730.  
  12731. use  Calendar;
  12732. use  SPC_Numeric_Types;
  12733.  
  12734. package body Random is
  12735.  
  12736.    -- Body of random number generator package.
  12737.    -- Adapted from the Ada literature by
  12738.    -- Michael B. Feldman, The George Washington University,
  12739.    -- November 1990.
  12740.  
  12741.    Modulus : constant := 9_317;
  12742.  
  12743.    subtype Seed_Range is Medium_Integer range 0 .. Modulus - 1;
  12744.  
  12745.    Seed : Seed_Range;
  12746.    Default_Seed : Seed_Range;
  12747.  
  12748.    procedure Set_Seed
  12749.      (N : in     Medium_Positive) is separate;
  12750.  
  12751.    function Unit_Random
  12752.      return Medium_Float is separate;
  12753.  
  12754.    function Random_Int
  12755.      (N : in     Medium_Positive)
  12756.      return Medium_Positive is separate;
  12757.  
  12758. begin
  12759.    Default_Seed :=
  12760.      Medium_Integer(Big_Integer(Seconds(Clock)) mod Modulus);
  12761.    Seed := Default_Seed;
  12762. end Random;
  12763.  
  12764. ------------------------------------------------------------------------
  12765.  
  12766. separate (Random)
  12767. procedure Set_Seed (N : in     Medium_Positive) is
  12768. begin
  12769.    Seed := Seed_Range(N);
  12770. end Set_Seed;
  12771.  
  12772. ------------------------------------------------------------------------
  12773.  
  12774. separate (Random)
  12775. function Unit_Random return Medium_Float is
  12776.  
  12777.    Multiplier : constant    := 421;
  12778.    Increment  : constant    := 2_073;
  12779.    Result     : Medium_Float;
  12780.  
  12781. begin  -- Unit_Random
  12782.  
  12783.    Seed  := (Multiplier * Seed + Increment) mod Modulus;
  12784.  
  12785.    Result := Medium_Float(Seed) / Medium_Float(Modulus);
  12786.    return Result;
  12787.  
  12788. exception
  12789.    when Constraint_Error | Numeric_Error =>
  12790.       Seed := Medium_Integer
  12791.            ((Multiplier * Big_Integer(Seed) + Increment) mod
  12792.         Modulus);
  12793.  
  12794.       Result := Medium_Float(Seed) / Medium_Float(Modulus);
  12795.       return Result;
  12796.  
  12797. end Unit_Random;
  12798.  
  12799. ------------------------------------------------------------------------
  12800.  
  12801. separate (Random)
  12802. function Random_Int (N : in     Medium_Positive)
  12803.       return Medium_Positive is
  12804.  
  12805.    Result : Medium_Positive range 1 .. N;
  12806.  
  12807. begin  -- Random_Int
  12808.  
  12809.    Result := Medium_Positive(Medium_Float(N) * Unit_Random + 0.5);
  12810.    return Result;
  12811.  
  12812. exception
  12813.    when Constraint_Error | Numeric_Error =>
  12814.       return 1;
  12815.  
  12816. end Random_Int;
  12817.  
  12818. ------------------------------------------------------------------------
  12819.  
  12820. package body Chop is
  12821.  
  12822.    task body Stick is
  12823.    begin
  12824.  
  12825.       loop
  12826.      select
  12827.         accept Pick_Up;
  12828.         accept Put_Down;
  12829.      or
  12830.         terminate;
  12831.      end select;
  12832.       end loop;
  12833.  
  12834.    -- No exception handler is needed here.
  12835.    end Stick;
  12836.  
  12837. end Chop;
  12838.  
  12839. ------------------------------------------------------------------------
  12840.  
  12841. with SPC_Numeric_Types;
  12842. with Room;
  12843. with Random;
  12844.  
  12845. use  SPC_Numeric_Types;
  12846.  
  12847. package body Phil is
  12848.  
  12849.    task body Philosopher is
  12850.  
  12851.       type Life_Time is range 1 .. 100_000;
  12852.  
  12853.       Who_Am_I    : Medium_Natural;
  12854.       First_Grab  : Medium_Natural;
  12855.       Second_Grab : Medium_Natural;
  12856.       Meal_Time   : Medium_Natural;
  12857.       Think_Time  : Medium_Natural;
  12858.  
  12859.    begin  -- Philosopher
  12860.       accept Come_To_Life (My_ID      : in     Medium_Natural;
  12861.                Chopstick1 : in     Medium_Natural;
  12862.                Chopstick2 : in     Medium_Natural) do
  12863.      Who_Am_I    := My_ID;
  12864.      First_Grab  := Chopstick1;
  12865.      Second_Grab := Chopstick2;
  12866.  
  12867.       end Come_To_Life;
  12868.  
  12869.       Room.Head_Waiter.Report_State(Who_Am_I, Breathing);
  12870.  
  12871.       for Meal in Life_Time loop
  12872.  
  12873.      Room.Sticks(First_Grab).Pick_Up;
  12874.      Room.Head_Waiter.Report_State
  12875.           (Who_Am_I, Got_One_Stick, First_Grab);
  12876.  
  12877.      Room.Sticks(Second_Grab).Pick_Up;
  12878.      Room.Head_Waiter.Report_State
  12879.           (Who_Am_I, Got_Other_Stick, Second_Grab);
  12880.  
  12881.      Meal_Time := Random.Random_Int(10);
  12882.      Room.Head_Waiter.Report_State(Who_Am_I, Eating, Meal_Time);
  12883.  
  12884.      delay Duration(Meal_Time);
  12885.      Room.Head_Waiter.Report_State(Who_Am_I, Done_Eating);
  12886.  
  12887.      Room.Sticks(First_Grab).Put_Down;
  12888.      Room.Sticks(Second_Grab).Put_Down;
  12889.  
  12890.      Think_Time := Random.Random_Int(10);
  12891.      Room.Head_Waiter.Report_State
  12892.           (Who_Am_I, Thinking, Think_Time);
  12893.      delay Duration(Think_Time);
  12894.  
  12895.       end loop;
  12896.  
  12897.    -- No exception handler is needed here.
  12898.    end Philosopher;
  12899.  
  12900. end Phil;
  12901.  
  12902. ------------------------------------------------------------------------
  12903.  
  12904. with SPC_Numeric_Types;
  12905. use  SPC_Numeric_Types;
  12906. with Text_IO;
  12907. with Chop;
  12908. with Phil;
  12909. with Calendar;
  12910.  
  12911. pragma Elaborate (Phil);
  12912. package body Room is
  12913.  
  12914.    -- A line-oriented version of the Room package, for line-oriented
  12915.    -- terminals like IBM 3270's where the user cannot do ASCII
  12916.    -- screen control.
  12917.    -- This is the only file in the dining philosophers system that
  12918.    -- needs changing to use in a line-oriented environment.
  12919.    -- Michael B. Feldman, The George Washington University,
  12920.    -- November 1990.
  12921.  
  12922.    Phils : array (Table_Type) of Phil.Philosopher;
  12923.  
  12924.    type Phil_Name is (Dijkstra, Texel, Booch, Ichbiah, Stroustrup);
  12925.  
  12926.    task body Head_Waiter is
  12927.  
  12928.       T : Medium_Natural;
  12929.       Start_Time : Calendar.Time;
  12930.  
  12931.       Phil_Names : constant array (Table_Type) of String (1 .. 18)
  12932.          := ("Eddy Dijkstra     ", "Putnam Texel      ",
  12933.              "Grady Booch       ", "Jean Ichbiah      ",
  12934.              "Bjarne Stroustrup ");
  12935.  
  12936.       Blanks : constant String := "     ";
  12937.  
  12938.    begin  -- Head_Waiter
  12939.  
  12940.       accept Open_The_Room;
  12941.       Start_Time := Calendar.Clock;
  12942.  
  12943.       Phils(1).Come_To_Life(1, 1, 2);
  12944.       Phils(3).Come_To_Life(3, 3, 4);
  12945.       Phils(2).Come_To_Life(2, 2, 3);
  12946.       Phils(5).Come_To_Life(5, 1, 5);
  12947.       Phils(4).Come_To_Life(4, 4, 5);
  12948.  
  12949.       loop
  12950.      select
  12951.         accept Report_State (Which_Phil : in     Table_Type;
  12952.                  State      : in     Phil.States;
  12953.                  How_Long   : in     Medium_Natural
  12954.                         := 0) do
  12955.            T := Medium_Natural
  12956.             (Calendar."-"(Calendar.Clock, Start_Time));
  12957.            Text_IO.Put ("T=" & Medium_Natural'Image(T) & " " &
  12958.                 Blanks(1 .. Positive(Which_Phil)) &
  12959.                 Phil_Names(Which_Phil));
  12960.  
  12961.            case State is
  12962.  
  12963.           when Phil.Breathing =>
  12964.              Text_IO.Put("Breathing");
  12965.  
  12966.           when Phil.Thinking =>
  12967.              Text_IO.Put ("Thinking" &
  12968.                   Medium_Natural'Image(How_Long) &
  12969.                   " seconds.");
  12970.  
  12971.           when Phil.Eating =>
  12972.              Text_IO.Put ("Eating" &
  12973.                   Medium_Natural'Image(How_Long) &
  12974.                   " seconds.");
  12975.  
  12976.           when Phil.Done_Eating =>
  12977.              Text_IO.Put("Yum-yum (burp)");
  12978.  
  12979.           when Phil.Got_One_Stick =>
  12980.              Text_IO.Put ("First chopstick" &
  12981.                   Medium_Natural'Image(How_Long));
  12982.  
  12983.           when Phil.Got_Other_Stick =>
  12984.              Text_IO.Put ("Second chopstick" &
  12985.                   Medium_Natural'Image(How_Long));
  12986.  
  12987.            end case;  -- State
  12988.  
  12989.            Text_IO.New_Line;
  12990.         end Report_State;
  12991.  
  12992.       or
  12993.         terminate;
  12994.      end select;
  12995.  
  12996.       end loop;
  12997.  
  12998.    -- An exception handler is not needed here.
  12999.    end Head_Waiter;
  13000.  
  13001. end Room;
  13002.  
  13003. ------------------------------------------------------------------------
  13004.  
  13005. 10.3    WINDOW-ORIENTED PORTABLE DINING PHILOSOPHERS EXAMPLE
  13006.  
  13007. Michael B. Feldman
  13008. Dept. of Electrical Engineering and Computer Science
  13009. The George Washington University
  13010. Washington, DC 20052
  13011.  
  13012. (202) 994-5253
  13013. mfeldman@seas.gwu.edu
  13014.  
  13015. Copyright 1991, Michael B. Feldman
  13016.  
  13017. These programs may be freely copied, distributed, and modified for educational
  13018. purposes but not for profit.  If you modify or enhance the program (for
  13019. example, to use other display systems), please send Dr. Feldman a copy of the
  13020. modified code, either on diskette or by e-mail.
  13021.  
  13022. This system is an elaborate implementation of Edsger Dijkstra's famous Dining 
  13023. Philosophers; a classical demonstration of deadlock problems in concurrent 
  13024. programming.
  13025.  
  13026. This example builds on some of the utilities found in the Line-Oriented 
  13027. example.
  13028.  
  13029. ------------------------------------------------------------------------
  13030. package Screen is
  13031.  
  13032.    -- Procedures for drawing pictures on ANSI Terminal Screen
  13033.  
  13034.    Screen_Depth : constant := 24;
  13035.    Screen_Width : constant := 80;
  13036.  
  13037.    subtype Depth is Integer range 1 .. Screen_Depth;
  13038.    subtype Width is Integer range 1 .. Screen_Width;
  13039.  
  13040.    procedure Beep;
  13041.    procedure Clear_Screen;
  13042.    procedure Move_Cursor (Column : in     Width;
  13043.               Row    : in     Depth);
  13044.  
  13045. end Screen;
  13046.  
  13047. ------------------------------------------------------------------------
  13048.  
  13049. with Screen;
  13050. use  Screen;
  13051. package Windows is
  13052.  
  13053.    type Window is private;
  13054.  
  13055.    procedure Open
  13056.      (W      : in out Window;       -- Window variable returned
  13057.       Row    : in     Depth;        -- Upper left corner
  13058.       Column : in     Width;
  13059.       Height : in     Depth;        -- Size of window
  13060.       Width  : in     Screen.Width);
  13061.  
  13062.    -- Create a window variable and open the window for writing.
  13063.    -- No checks for overlap of windows are made.
  13064.  
  13065.    procedure Close (W : in out Window);
  13066.    -- Close window and clear window variable.
  13067.  
  13068.    procedure Title (W     : in out Window;
  13069.             Name  : in     String;
  13070.             Under : in     Character);
  13071.  
  13072.    -- Put a title name at the top of the window.  If the parameter
  13073.    -- Under is nonblank, underline the title with the
  13074.    -- specified character.
  13075.  
  13076.    procedure Borders (W      : in out Window;
  13077.               Corner : in     Character;
  13078.               Down   : in     Character;
  13079.               Across : in     Character);
  13080.  
  13081.    -- Draw border around current writable area in window with
  13082.    -- characters specified.  Call this BEFORE Title.
  13083.  
  13084.    procedure Go_To_Row_Column (W      : in out Window;
  13085.                    Row    : in     Depth;
  13086.                    Column : in     Width);
  13087.  
  13088.    -- Goto the row and column specified.  Coordinates are relative
  13089.    -- to the upper left corner of window, which is (1, 1)
  13090.  
  13091.    procedure Put
  13092.      (W  : in out Window;
  13093.       Ch : in     Character);
  13094.  
  13095.    -- put one character to the window.
  13096.    -- If end of column, go to the next row.
  13097.    -- If end of window, go to the top of the window.
  13098.  
  13099.    procedure Put_String (W : in out Window;
  13100.              S : in     String);
  13101.  
  13102.    -- put a string to window.
  13103.  
  13104.    procedure New_Line (W : in out Window);
  13105.  
  13106.    -- Go to beginning of next line.  Next line is
  13107.    -- not blanked until next character is written
  13108.  
  13109. private
  13110.  
  13111.    type Window is
  13112.       record
  13113.      Current_Row    : Depth;          -- Current cursor row
  13114.      First_Row      : Depth;
  13115.      Last_Row       : Depth;
  13116.  
  13117.      Current_Column : Width;          -- Current cursor column
  13118.      First_Column   : Width;
  13119.      Last_Column    : Width;
  13120.  
  13121.       end record;
  13122.  
  13123. end Windows;
  13124.  
  13125. ------------------------------------------------------------------------
  13126.  
  13127. with Text_IO;
  13128. package body Screen is
  13129.  
  13130.    package My_Int_IO is new Text_IO.Integer_IO (Integer);
  13131.  
  13132.    -- Procedures for drawing pictures on ANSI Terminal Screen
  13133.  
  13134.    ---------------------------------------------------------------------
  13135.    procedure Beep is
  13136.    begin
  13137.       Text_IO.Put(Item => ASCII.Bel);
  13138.    end Beep;
  13139.  
  13140.    ---------------------------------------------------------------------
  13141.  
  13142.    procedure Clear_Screen is
  13143.    begin
  13144.       Text_IO.Put(Item => ASCII.Esc);
  13145.       Text_IO.Put(Item => "[2J");
  13146.    end Clear_Screen;
  13147.  
  13148.    ---------------------------------------------------------------------
  13149.  
  13150.    procedure Move_Cursor (Column : in     Width;
  13151.               Row    : in     Depth) is
  13152.    begin
  13153.       Text_IO.New_Line;
  13154.       Text_IO.Put(Item => ASCII.Esc);
  13155.       Text_IO.Put("[");
  13156.       My_Int_IO.Put (Item  => Row,
  13157.              Width => 1);
  13158.       Text_IO.Put(Item => ';');
  13159.       My_Int_IO.Put (Item  => Column,
  13160.              Width => 1);
  13161.       Text_IO.Put(Item => 'f');
  13162.    end Move_Cursor;
  13163.  
  13164.    ---------------------------------------------------------------------
  13165.  
  13166. end Screen;
  13167.  
  13168. ------------------------------------------------------------------------
  13169.  
  13170. with Text_IO;
  13171. with Medium_Integer_IO;
  13172. with Screen;
  13173.  
  13174. use  Text_IO;
  13175. use  Medium_Integer_IO;
  13176. use  Screen;
  13177.  
  13178. package body Windows is
  13179.  
  13180.    Cursor_Row : Depth := 1;            -- Current cursor position
  13181.    Cursor_Col : Width := 1;
  13182.  
  13183.    ---------------------------------------------------------------------
  13184.    procedure Open
  13185.      (W      : in out Window;
  13186.       Row    : in     Depth;
  13187.       Column : in     Width;
  13188.       Height : in     Depth;
  13189.       Width  : in     Screen.Width) is
  13190.  
  13191.       --Put the Window's cursor in upper left corner
  13192.    begin
  13193.       W.Current_Row := Row;
  13194.       W.First_Row := Row;
  13195.       W.Last_Row := Row + Height - 1;
  13196.  
  13197.       W.Current_Column := Column;
  13198.       W.First_Column := Column;
  13199.       W.Last_Column := Column + Width - 1;
  13200.    end Open;
  13201.  
  13202.    ---------------------------------------------------------------------
  13203.  
  13204.    procedure Close (W : in out Window) is
  13205.    begin
  13206.       null;
  13207.    end Close;
  13208.  
  13209.    ---------------------------------------------------------------------
  13210.  
  13211.    procedure Title (W     : in out Window;
  13212.             Name  : in     String;
  13213.             Under : in     Character) is
  13214.  
  13215.       -- Put name at the top of the Window.  If Under nonblank,
  13216.       -- underline the title.
  13217.    begin
  13218.       -- Put name on top line
  13219.       W.Current_Column := W.First_Column;
  13220.       W.Current_Row := W.First_Row;
  13221.       Put_String(W, Name);
  13222.       New_Line(W);
  13223.  
  13224.       -- Underline name if desired, and move the First line
  13225.       -- of the Window below the title
  13226.       if Under = ' ' then
  13227.      W.First_Row := W.First_Row + 1;
  13228.  
  13229.       else  -- put nonblank characters under title
  13230.      for I in W.First_Column .. W.Last_Column loop
  13231.         Put(W, Under);
  13232.      end loop;
  13233.      New_Line(W);
  13234.      W.First_Row := W.First_Row + 2;
  13235.       end if;
  13236.  
  13237.    end Title;
  13238.  
  13239.    ---------------------------------------------------------------------
  13240.  
  13241.    procedure Go_To_Row_Column (W      : in out Window;
  13242.                    Row    : in     Depth;
  13243.                    Column : in     Width) is
  13244.  
  13245.       -- Relative to writable Window boundaries, of course
  13246.    begin
  13247.       W.Current_Row    := W.First_Row    + Row;
  13248.       W.Current_Column := W.First_Column + Column;
  13249.    end Go_To_Row_Column;
  13250.  
  13251.    ---------------------------------------------------------------------
  13252.  
  13253.    procedure Borders (W      : in out Window;
  13254.               Corner : in     Character;
  13255.               Down   : in     Character;
  13256.               Across : in     Character) is
  13257.  
  13258.       -- Draw border around current writable area in Window
  13259.       -- with characters. Call this BEFORE Title.
  13260.    begin
  13261.  
  13262.       -- Put top line of border
  13263.       Screen.Move_Cursor(W.First_Column, W.First_Row);
  13264.       Text_IO.Put(Corner);
  13265.  
  13266.       for J in W.First_Column + 1 .. W.Last_Column - 1 loop
  13267.      Text_IO.Put(Across);
  13268.       end loop;
  13269.       Text_IO.Put(Corner);
  13270.  
  13271.       -- Put the two side lines
  13272.       for I in W.First_Row + 1 .. W.Last_Row - 1 loop
  13273.      Screen.Move_Cursor(W.First_Column, I);
  13274.      Text_IO.Put(Down);
  13275.      Screen.Move_Cursor(W.Last_Column, I);
  13276.      Text_IO.Put(Down);
  13277.       end loop;
  13278.  
  13279.       -- Put the bottom line of the border
  13280.       Screen.Move_Cursor(W.First_Column, W.Last_Row);
  13281.       Text_IO.Put(Corner);
  13282.       for J in W.First_Column + 1 .. W.Last_Column - 1 loop
  13283.      Text_IO.Put(Across);
  13284.       end loop;
  13285.       Text_IO.Put(Corner);
  13286.  
  13287.       -- Put the cursor at the very end of the Window
  13288.       Cursor_Row := W.Last_Row;
  13289.       Cursor_Col := W.Last_Column + 1;
  13290.  
  13291.       -- Make the Window smaller by one character on each side
  13292.       W.First_Row := W.First_Row + 1;
  13293.       W.Current_Row := W.First_Row;
  13294.       W.Last_Row := W.Last_Row - 1;
  13295.       W.First_Column := W.First_Column + 1;
  13296.       W.Current_Column := W.First_Column;
  13297.       W.Last_Column := W.Last_Column - 1;
  13298.    end Borders;
  13299.  
  13300.    ---------------------------------------------------------------------
  13301.  
  13302.    procedure Erase_To_End_Of_Line (W : in out Window) is
  13303.    begin
  13304.       Screen.Move_Cursor(W.Current_Column, W.Current_Row);
  13305.  
  13306.       for I in W.Current_Column .. W.Last_Column loop
  13307.      Text_IO.Put(' ');
  13308.       end loop;
  13309.  
  13310.       Screen.Move_Cursor(W.Current_Column, W.Current_Row);
  13311.       Cursor_Col := W.Current_Column;
  13312.       Cursor_Row := W.Current_Row;
  13313.    end Erase_To_End_Of_Line;
  13314.  
  13315.    ---------------------------------------------------------------------
  13316.  
  13317.    procedure Put (W  : in out Window;
  13318.           Ch : in     Character) is
  13319.  
  13320.       -- If after end of line, move to First character of next line
  13321.       -- If about to write First character on line, blank rest of
  13322.       -- line.
  13323.       -- Put character.
  13324.  
  13325.    begin
  13326.       if Ch = ASCII.CR then
  13327.      New_Line(W);
  13328.  
  13329.      return;
  13330.  
  13331.       end if;
  13332.  
  13333.       -- If at end of current line, move to next line
  13334.       if W.Current_Column > W.Last_Column then
  13335.  
  13336.      if W.Current_Row = W.Last_Row then
  13337.         W.Current_Row := W.First_Row;
  13338.  
  13339.      else  -- not at end of current line
  13340.         W.Current_Row := W.Current_Row + 1;
  13341.      end if;
  13342.  
  13343.      W.Current_Column := W.First_Column;
  13344.       end if;
  13345.  
  13346.       -- If at W.First char, erase line
  13347.       if W.Current_Column = W.First_Column then
  13348.      Erase_To_End_Of_Line(W);
  13349.       end if;
  13350.  
  13351.       -- Put physical cursor at Window's cursor
  13352.       if Cursor_Col /= W.Current_Column or
  13353.      Cursor_Row /= W.Current_Row    then
  13354.  
  13355.      Screen.Move_Cursor(W.Current_Column, W.Current_Row);
  13356.      Cursor_Row := W.Current_Row;
  13357.       end if;
  13358.  
  13359.       if Ch = ASCII.BS then
  13360.      -- Special backspace handling
  13361.      if W.Current_Column /= W.First_Column then
  13362.         Text_IO.Put(Ch);
  13363.         W.Current_Column := W.Current_Column - 1;
  13364.      end if;
  13365.  
  13366.       else  -- character is not a backspace, so just write it
  13367.      Text_IO.Put(Ch);
  13368.      W.Current_Column := W.Current_Column + 1;
  13369.       end if;
  13370.  
  13371.       Cursor_Col := W.Current_Column;
  13372.    end Put;
  13373.  
  13374.    ---------------------------------------------------------------------
  13375.  
  13376.    procedure New_Line (W : in out Window) is
  13377.  
  13378.       Col : Width;
  13379.  
  13380.       -- If not after line, blank rest of line.
  13381.       -- Move to First character of next line
  13382.    begin  -- New_Line
  13383.  
  13384.       if W.Current_Column = 0 then
  13385.      Erase_To_End_Of_Line(W);
  13386.       end if;
  13387.  
  13388.       if W.Current_Row = W.Last_Row then
  13389.      W.Current_Row := W.First_Row;
  13390.  
  13391.       else  -- not at bottom of screen
  13392.      W.Current_Row := W.Current_Row + 1;
  13393.       end if;
  13394.  
  13395.       W.Current_Column := W.First_Column;
  13396.    end New_Line;
  13397.  
  13398.    ---------------------------------------------------------------------
  13399.  
  13400.    procedure Put_String (W : in out Window;
  13401.              S : in     String) is
  13402.    begin
  13403.       for I in S'First .. S'Last loop
  13404.      Put(W, S(I));
  13405.       end loop;
  13406.    end Put_String;
  13407.  
  13408.    ---------------------------------------------------------------------
  13409.  
  13410. begin  -- Windows
  13411.    Screen.Clear_Screen;
  13412.    Screen.Move_Cursor(1, 1);
  13413. end Windows;
  13414.  
  13415. ------------------------------------------------------------------------
  13416.  
  13417. with SPC_Numeric_Types;
  13418. with Windows;
  13419. with Chop;
  13420. with Phil;
  13421. with Calendar;
  13422.  
  13423. use  SPC_Numeric_Types;
  13424.  
  13425. pragma Elaborate (Phil);
  13426. package body Room is
  13427.  
  13428.    Phils        : array (Table_Type) of Phil.Philosopher;
  13429.    Phil_Windows : array (Table_Type) of Windows.Window;
  13430.  
  13431.    type Phil_Names is (Dijkstra, Texel, Booch, Ichbiah, Stroustrup);
  13432.  
  13433.    task body Head_Waiter is
  13434.  
  13435.       T          : Medium_Positive;
  13436.       Start_Time : Calendar.Time;
  13437.  
  13438.    begin  -- Head_Waiter
  13439.  
  13440.       accept Open_The_Room;
  13441.       Start_Time := Calendar.Clock;
  13442.  
  13443.       Windows.Open (W      => Phil_Windows(1),
  13444.             Row    => 1,
  13445.             Column => 23,
  13446.             Height => 7,
  13447.             Width  => 30);
  13448.  
  13449.       Windows.Borders(Phil_Windows(1), '+', '|', '-');
  13450.       Windows.Title  (Phil_Windows(1), "Eddy Dijkstra", '-');
  13451.       Phils(1).Come_To_Life(1, 1, 2);
  13452.  
  13453.       Windows.Open (W      => Phil_Windows(3),
  13454.             Row    => 9,
  13455.             Column => 50,
  13456.             Height => 7,
  13457.             Width  => 30);
  13458.  
  13459.       Windows.Borders(Phil_Windows(3), '+', '|', '-');
  13460.       Windows.Title  (Phil_Windows(3), "Grady Booch", '-');
  13461.       Phils(3).Come_To_Life(3, 3, 4);
  13462.  
  13463.       Windows.Open (W      => Phil_Windows(2),
  13464.             Row    => 9,
  13465.             Column => 2,
  13466.             Height => 7,
  13467.             Width  => 30);
  13468.  
  13469.       Windows.Borders(Phil_Windows(2), '+', '|', '-');
  13470.       Windows.Title  (Phil_Windows(2), "Putnam Texel", '-');
  13471.       Phils(2).Come_To_Life(2, 2, 3);
  13472.  
  13473.       Windows.Open (W      => Phil_Windows(5),
  13474.             Row    => 17,
  13475.             Column => 41,
  13476.             Height => 7,
  13477.             Width  => 30);
  13478.  
  13479.       Windows.Borders(Phil_Windows(5), '+', '|', '-');
  13480.       Windows.Title  (Phil_Windows(5), "Bjarne Stroustrup", '-');
  13481.       Phils(5).Come_To_Life(5, 1, 5);
  13482.  
  13483.       Windows.Open (W      => Phil_Windows(4),
  13484.             Row    => 17,
  13485.             Column => 8,
  13486.             Height => 7,
  13487.             Width  => 30);
  13488.  
  13489.       Windows.Borders(Phil_Windows(4), '+', '|', '-');
  13490.       Windows.Title  (Phil_Windows(4), "Jean Ichbiah", '-');
  13491.       Phils(4).Come_To_Life(4, 4, 5);
  13492.  
  13493.       loop
  13494.      select
  13495.         accept Report_State
  13496.           (Which_Phil : in     Table_Type;
  13497.            State      : in     Phil.States;
  13498.            How_Long   : in     Medium_Natural := 0) do
  13499.            T :=
  13500.              Medium_Natural
  13501.             (Calendar."-"(Calendar.Clock, Start_Time));
  13502.            Windows.Put_String
  13503.             (Phil_Windows(Which_Phil),
  13504.              "T=" & Medium_Natural'Image(T) & " ");
  13505.            case State is
  13506.           when Phil.Breathing =>
  13507.              Windows.Put_String
  13508.                   (Phil_Windows(Which_Phil),
  13509.                    "Breathing...");
  13510.              Windows.New_Line(Phil_Windows(Which_Phil));
  13511.  
  13512.           when Phil.Thinking =>
  13513.              Windows.Put_String
  13514.             (Phil_Windows(Which_Phil),
  13515.              "Thinking" & Medium_Natural'Image(How_Long) &
  13516.              " seconds.");
  13517.              Windows.New_Line(Phil_Windows(Which_Phil));
  13518.  
  13519.           when Phil.Eating =>
  13520.              Windows.Put_String
  13521.             (Phil_Windows(Which_Phil),
  13522.              "Eating" & Medium_Natural'Image(How_Long) &
  13523.              " seconds.");
  13524.              Windows.New_Line(Phil_Windows(Which_Phil));
  13525.  
  13526.           when Phil.Done_Eating =>
  13527.              Windows.Put_String
  13528.                   (Phil_Windows(Which_Phil),
  13529.                    "Yum-yum (burp)");
  13530.              Windows.New_Line(Phil_Windows(Which_Phil));
  13531.  
  13532.           when Phil.Got_One_Stick =>
  13533.              Windows.Put_String
  13534.             (Phil_Windows(Which_Phil),
  13535.              "First chopstick" &
  13536.              Medium_Natural'Image(How_Long));
  13537.              Windows.New_Line(Phil_Windows(Which_Phil));
  13538.  
  13539.           when Phil.Got_Other_Stick =>
  13540.              Windows.Put_String
  13541.             (Phil_Windows(Which_Phil),
  13542.              "Second chopstick" &
  13543.              Medium_Natural'Image(How_Long));
  13544.              Windows.New_Line(Phil_Windows(Which_Phil));
  13545.  
  13546.            end case;
  13547.  
  13548.         end Report_State;
  13549.      or
  13550.         terminate;
  13551.      end select;
  13552.  
  13553.       end loop;
  13554.  
  13555.    -- An exception handler is not needed here.
  13556.    end Head_Waiter;
  13557.  
  13558. end Room;
  13559. ------------------------------------------------------------------------
  13560.  
  13561.  
  13562.  
  13563. APPENDIX A
  13564. Map from Ada Language Reference Manual to Guidelines
  13565.  
  13566.  
  13567.  
  13568.  
  13569. 1.        Introduction
  13570.  
  13571. 1.1       Scope of the Standard
  13572.  
  13573. 1.1.1     Extent of the Standard
  13574.  
  13575. 1.1.2     Conformity of an Implementation with the Standard
  13576.  
  13577. 1.2       Structure of the Standard
  13578.  
  13579. 1.3       Design Goals and Sources
  13580.  
  13581. 1.4       Language Summary
  13582.  
  13583. 1.5       Method of Description and Syntax Notation                    2.1.8
  13584.  
  13585. 1.6       Classification of Errors                                       5.9
  13586.  
  13587. 2.        Lexical Elements
  13588.  
  13589. 2.1       Character Set
  13590.  
  13591. 2.2       Lexical Elements, Separators, and Delimiters                 2.1.1
  13592.  
  13593. 2.3       Identifiers                               3.1.1, 3.1.3, 3.1.4, 3.2   
  13594.                           5.2.1, 5.5.4, 8.1.1, 8.1.2
  13595.  
  13596. 2.4       Numeric Literals                               3.1.2, 3.2.5, 7.2.6
  13597.  
  13598. 2.4.1     Decimal Literals
  13599.  
  13600. 2.4.2     Based Literals
  13601.  
  13602. 2.5       Character Literals                                           3.2.5
  13603.  
  13604. 2.6       String Literals                         2.1.1, 2.1.2, 2.1.4, 3.2.5
  13605.  
  13606. 2.7       Comments                           2.1.4, 2.1.7, 3.3, 5.2.1, 5.6.7
  13607.                        5.6.8, 7.1.3, 7.1.5, 7.2.5, 8.3.5
  13608.  
  13609. 2.8       Pragmas                                               8.4.2, 9.1.1
  13610.  
  13611. 2.9       Reserved Words                                               3.1.3
  13612.  
  13613. 2.10      Allowable Replacements of Characters
  13614.  
  13615. 3.        Declarations and Types             2.1.4, 2.1.6, 2.1.8, 4.1.4, 5.3
  13616.                      
  13617. 3.1       Declarations                                                 3.2.1
  13618.  
  13619. 3.2       Objects and Named Numbers        3.2.3, 3.2.5, 4.1.5, 7.2.6, 8.2.1
  13620.  
  13621. 3.2.1     Object Declarations                                   4.1.6, 5.9.6
  13622.  
  13623. 3.2.2     Number Declarations
  13624.  
  13625. 3.3       Types and Subtypes        3.2.2, 3.4.1, 4.1.5, 7.2.7, 8.2.3, 9.1.5
  13626.  
  13627. 3.3.1     Type Declarations                                            3.3.5
  13628.  
  13629. 3.3.2     Subtype Declarations      5.3.1, 5.5.1, 5.6.3, 5.7.2, 7.2.7, 9.1.5
  13630.  
  13631. 3.3.3     Classification of Operations 
  13632.  
  13633. 3.4       Derived Types                           3.4.1, 5.3.1, 7.2.7, 9.1.5
  13634.  
  13635. 3.5       Scalar Types                                   3.4.1, 5.3.1, 5.5.1
  13636.  
  13637. 3.5.1     Enumeration Types                       2.1.4, 3.4.2, 5.6.3, 5.7.1
  13638.  
  13639. 3.5.2     Character Types     
  13640.                            
  13641. 3.5.3     Boolean Types                                                3.2.3
  13642.  
  13643. 3.5.4     Integer Types                           7.1.1, 7.1.2, 7.2.1, 7.2.5
  13644.  
  13645. 3.5.5     Operations of Discrete Types
  13646.  
  13647. 3.5.6     Real Types                              7.1.1, 7.1.2, 5.5.6, 7.2.5
  13648.  
  13649. 3.5.7     Floating Point Types                           7.2.1, 7.2.2, 7.2.3
  13650.  
  13651. 3.5.8     Operations of Floating Point Types
  13652.  
  13653. 3.5.9     Fixed Point Types                                     7.1.1, 7.2.1
  13654.  
  13655. 3.5.10    Operations of Fixed Point Types
  13656.  
  13657. 3.6       Array Types                             5.3.2, 5.5.1, 5.5.2, 5.9.3 
  13658.                              8.2.2, 8.3.4, 9.1.3
  13659.  
  13660. 3.6.1     Index Constraints and Discrete Ranges                 5.5.2, 9.1.3
  13661.  
  13662. 3.6.2     Operations of Array Types                                    5.6.2
  13663.  
  13664. 3.6.3     The Type String                                              2.1.1
  13665.  
  13666. 3.7       Record Types                     2.1.2, 5.4.1, 5.4.2, 5.4.3, 5.9.3
  13667.  
  13668. 3.7.1     Discriminants
  13669.  
  13670. 3.7.2     Discriminant Constraints
  13671.  
  13672. 3.7.3     Variant Parts
  13673.  
  13674. 3.7.4     Operations of Record Types
  13675.  
  13676. 3.8       Access Types                     5.4.3, 5.9.2, 6.1.3, 7.6.6, 7.7.3
  13677.  
  13678. 3.8.1     Incomplete Type Declarations                                 5.4.3
  13679.  
  13680. 3.8.2     Operations of Access Types      
  13681.  
  13682. 3.9       Declarative Parts                                     2.1.4, 5.9.6
  13683.  
  13684. 4.        Names and Expressions
  13685.  
  13686. 4.1       Names                                            3.2, 8.1.1, 8.1.2
  13687.  
  13688. 4.1.1     Indexed Components
  13689.  
  13690. 4.1.2     Slices                                                       5.6.2
  13691.  
  13692. 4.1.3     Selected Components
  13693.                       
  13694. 4.1.4     Attributes                                                   8.2.4
  13695.  
  13696. 4.2       Literals                                                     8.2.4
  13697.  
  13698. 4.3       Aggregates                   
  13699.  
  13700. 4.3.1     Record Aggregates                                           5.6.10
  13701.  
  13702. 4.3.2     Array Aggregates 
  13703.  
  13704. 4.4       Expressions                 2.1.1, 2.1.3, 2.1.5, 5.5, 5.5.3, 7.2.7
  13705.  
  13706. 4.5       Operators and Expression Evaluation                  2.1.1, 2.1.3, 
  13707.                        5.5.3, 5.7.1, 5.7.2, 5.7.4, 7.2.7
  13708.  
  13709. 4.5.1     Logical Operators and Short-circuit Control Forms     5.5.4, 5.5.5
  13710.  
  13711. 4.5.2     Relational Operators and Membership Tests     2.1.1, 5.5.6, 5.7.5, 
  13712.                                        7.2.8 
  13713.  
  13714. 4.5.3     Binary Adding Operators                               2.1.1, 5.7.4
  13715.  
  13716. 4.5.4     Unary Adding Operators
  13717.  
  13718. 4.5.5.    Multiplying Operators                                        9.1.5
  13719.  
  13720. 4.5.6     Highest Precedence Operators            5.5.3
  13721.  
  13722. 4.5.7     Accuracy of Operations with Real Operands                   5.5.6, 
  13723.                        7.2.2, 7.2.3, 7.2.4, 7.2.5, 7.2.7
  13724.  
  13725. 4.6       Type Conversions                                             5.9.1
  13726.  
  13727. 4.7       Qualified Expressions
  13728.  
  13729. 4.8       Allocators                                     5.4.3, 6.1.3, 7.6.6
  13730.  
  13731. 4.9       Static Expressions and Static Subtypes         3.2.5, 7.2.6, 8.2.1
  13732.  
  13733. 4.10      Universal Expressions                                        7.2.6
  13734.  
  13735. 5.        Statements                         2.1.2, 2.1.6, 2.1.8, 3.3.6, 5.6
  13736.  
  13737. 5.1       Simple and Compound Statements - Sequences of Statements     5.6.1
  13738.  
  13739. 5.2       Assignment Statement                                  2.1.3, 5.6.2
  13740.  
  13741. 5.2.1     Array Assignments
  13742.  
  13743. 5.3       If Statements                           2.1.5, 3.3.7, 5.6.1, 5.6.5
  13744.  
  13745. 5.4       Case Statements                                3.3.7, 5.6.1, 5.6.3
  13746.  
  13747. 5.5       Loop Statements    5.1.1, 5.5.1, 5.6.1, 5.6.2, 5.6.4, 5.6.6, 7.4.2
  13748.  
  13749. 5.6       Block Statements          3.3.7, 5.1.2, 5.6.1, 5.6.9, 5.8.4, 9.1.2 
  13750.  
  13751. 5.7       Exit Statements                         5.1.3, 5.6.4, 5.6.4, 5.6.5
  13752.  
  13753. 5.8       Return Statements                                            5.6.8
  13754.  
  13755. 5.9       Goto Statements                                       5.6.7, 5.8.1
  13756.  
  13757. 6.        Subprograms                                                  4.1.2
  13758.  
  13759. 6.1       Subprogram Declarations                       2.1.2, 3.2.4, 3.3.3, 
  13760.                       4.1.1, 4.1.4, 4.1.5, 4.2.1, 4.3.1,
  13761.                           5.2.1, 5.6.6, 7.1.3, 7.1.4
  13762.                         
  13763. 6.2       Formal Parameter Modes                         2.1.5, 5.2.4, 5.9.3
  13764.  
  13765. 6.3       Subprogram Bodies                2.1.7, 3.3.4, 3.3.7, 5.1.4, 9.1.1 
  13766.  
  13767. 6.3.1     Conformance Rules
  13768.  
  13769. 6.3.2     Inline Expansion of Subprograms                              9.1.1
  13770.  
  13771. 6.4       Subprogram Calls                 2.1.1, 4.1.3, 5.2.2, 5.6.6, 5.9.3
  13772.  
  13773. 6.4.1     Parameter Associations                                5.2.2, 5.9.8 
  13774.  
  13775. 6.4.2     Default Parameters                                    5.2.2, 5.2.3
  13776.  
  13777. 6.5       Function Subprograms             2.1.1, 3.2.4, 4.1.3, 4.3.1, 5.9.6
  13778.  
  13779. 6.6       Parameter and Result Type Profile - 
  13780.         Overloading of Subprograms                                 4.2.1
  13781.                                 5.7.3, 8.2.5
  13782.  
  13783. 6.7       Overloading of Operators                                     5.7.5
  13784.  
  13785. 7.        Packages                                       2.1.2, 4.1.4, 4.1.5
  13786.  
  13787. 7.1       Package Structure                                4.2.1, 4.3, 7.1.5
  13788.  
  13789. 7.2       Package Specifications and Declarations       2.1.7, 3.2.4, 3.3.3,
  13790.                    4.1.1, 4.1.6, 4.2.1, 4.2.2, 4.2.4, 4.3.1,
  13791.                        5.1.4, 7.1.3, 7.1.5, 8.2.6, 8.3.1
  13792.  
  13793. 7.3       Package Bodies                                        2.1.7, 3.3.4
  13794.                        4.1.1, 4.2.1, 4.3.1, 5.1.4, 5.9.1
  13795.  
  13796. 7.4       Private Type and Deferred Constant Declarations              5.3.3
  13797.  
  13798. 7.4.1     Private Types                                                5.3.3
  13799.  
  13800. 7.4.2     Operations of a Private Type
  13801.  
  13802. 7.4.3     Deferred Constants
  13803.  
  13804. 7.4.4     Limited Types                                  5.3.3, 5.7.5, 8.3.4
  13805.  
  13806. 7.5       Example of a Table Management Package
  13807.  
  13808. 7.6       Example of a Text Handling Package
  13809.  
  13810. 8.        Visibility Rules                                          4.2, 5.7
  13811.  
  13812. 8.1       Declarative Region                                           4.2.3 
  13813.  
  13814. 8.2       Scope of Declarations                          4.1.6, 4.2.3, 7.6.6
  13815.  
  13816. 8.3       Visibility                4.1.3, 4.1.4, 4.2.1, 4.2.3, 5.7.1, 5.7.3
  13817.  
  13818. 8.4       Use Clauses                                    5.6.9, 5.7.1, 5.7.2
  13819.  
  13820. 8.5       Renaming Declarations                          5.6.9, 5.7.1, 5.7.2
  13821.  
  13822. 8.6       The Package Standard                                  3.2.2, 7.2.1
  13823.  
  13824. 8.7       The Context of Overload Resolution                           8.2.5
  13825.  
  13826. 9.        Tasks                                         4.1.7, 4.2.4, 6, 7.4
  13827.  
  13828. 9.1       Task Specifications and Task Bodies     2.1.7, 3.2.4, 3.3.7, 5.1.4
  13829.                        6.1.1, 6.1.4, 6.3.4, 7.1.3, 8.4.2
  13830.  
  13831. 9.2       Task Types and Task Objects                           6.1.1, 6.1.2  
  13832.  
  13833. 9.3       Task Execution - Task Activation       6.1.3, 6.1.4, 6.1.5, 6.3.2,
  13834.                           7.4.1, 7.4.2, 7.4.5, 8.2.6
  13835.  
  13836. 9.4       Task Dependence - Termination of Tasks                  6.2.3, 6.3 
  13837.     
  13838. 9.5       Entries, Entry Calls, and Accept Statements          3.2.4, 4.3.1,
  13839.                       5.1.4, 5.2.1, 5.2.4, 5.6.1, 5.9.4,
  13840.                       6.1.4, 6.2, 6.3.1, 6.3.2, 7.4.5, 7.4.7
  13841.  
  13842. 9.6       Delay Statements, Duration, and Time          6.1.5, 6.2.5, 7.1.1, 
  13843.                                 7.4.2, 7.4.3 
  13844.  
  13845. 9.7       Select Statements                       2.1.2, 5.6.1, 6.2.1, 6.2.6
  13846.  
  13847. 9.7.1     Selective Waits           6.2.1, 6.2.2, 6.2.4, 6.2.5, 6.3.2, 7.4.4
  13848.  
  13849. 9.7.2     Conditional Entry Calls                               4.2.4, 6.2.5
  13850.  
  13851. 9.7.3     Timed Entry Calls                              4.2.4, 6.1.5, 6.2.5
  13852.  
  13853. 9.8       Priorities                                     6.1.4, 7.4.5, 8.4.2
  13854.  
  13855. 9.9       Task and Entry Attributes                                    6.2.3
  13856.  
  13857. 9.10      Abort Statements                                      6.3.3, 7.4.6
  13858.  
  13859. 9.11      Shared Variables                                      6.2.4, 7.4.7
  13860.  
  13861. 9.12      Example of Tasking
  13862.  
  13863. 10        Program Structure and Compilation Issues                     4.1.1
  13864.  
  13865. 10.1      Compilation Units - Library Units              3.3.2, 4.1.1, 7.1.4
  13866.  
  13867. 10.1.1    Context Clauses - With Clauses                2.1.2, 4.2.1, 4.2.3, 
  13868.                              8.2.6, 8.4.1, 8.4.2
  13869.  
  13870. 10.1.2    Examples of Compilation Units                
  13871.  
  13872. 10.2      Subunits of Compilation Units                         4.1.1, 4.2.3
  13873.  
  13874. 10.2.1    Examples of Subunits
  13875.  
  13876. 10.3      Order of Compilation
  13877.  
  13878. 10.4      The Program Library                                            8.4
  13879.  
  13880. 10.5      Elaboration of Library Units                                 8.4.2
  13881.  
  13882. 10.6      Program Optimization                                         8.4.4
  13883.  
  13884. 11.       Exceptions                                           4.3, 5.8, 7.5
  13885.  
  13886. 11.1      Exception Declarations           3.3.5, 4.3.1, 5.4.3, 7.5.2, 7.5.3
  13887.  
  13888. 11.2      Exception Handlers       2.1.2, 4.3.1, 5.6.9, 5.8.1, 5.8.2, 5.8.3, 
  13889.                    5.8.4, 6.2.2, 6.3.1, 6.3.4, 7.5.2, 7.5.3, 
  13890.                                        8.2.7
  13891.  
  13892. 11.3      Raise Statements                        4.3.1, 7.5.3, 8.2.3, 8.2.7
  13893.  
  13894. 11.4      Exception Handling               4.3.1, 5.8.1, 5.8.2, 5.8.3, 5.8.4
  13895.                             6.2.2, 6.3.4, 7.5, 8.2.7
  13896.       
  13897. 11.4.1    Exceptions Raised During the Execution of Statements         5.8.1 
  13898.  
  13899. 11.4.2    Exceptions Raised During the Elaboration of Declarations     5.8.1
  13900.  
  13901. 11.5      Exceptions Raised During Task Communication           5.8.1, 6.2.2 
  13902.  
  13903. 11.6      Exceptions and Optimization                
  13904.  
  13905. 11.7      Suppressing Checks                                           5.9.5  
  13906.  
  13907. 12.       Generic Units                               
  13908.                                
  13909. 12.1      Generic Declarations                           2.1.2, 3.2.4, 4.2.2
  13910.                       8.1.1, 8.1.2, 8.1.3, 8.3.1, 8.3.2,
  13911.                        8.3.3, 8.3.4, 8.3.5, 8.4.1, 8.4.3
  13912.  
  13913. 12.1.1    Generic Formal Objects                                8.2.4, 8.2.6 
  13914.  
  13915. 12.1.2    Generic Formal Types                    8.2.2, 8.3.3, 8.3.4, 8.3.6 
  13916.  
  13917. 12.1.3    Generic Formal Subprograms                                   8.3.6
  13918.  
  13919. 12.2      Generic Bodies                                               8.2.7
  13920.  
  13921. 12.3      Generic Instantiation                         2.1.2, 3.2.4, 5.2.2,
  13922.                     8.1.1, 8.2.4, 8.2.5, 8.3.2, 8.3.6, 8.4.4
  13923.  
  13924. 12.3.1    Matching Rules for Formal Objects
  13925.       
  13926. 12.3.2    Matching Rules for Formal Private Types               5.3.3, 8.3.4 
  13927.  
  13928. 12.3.3    Matching Rules for Formal Scalar Types
  13929.  
  13930. 12.3.4    Matching Rules for Formal Array Types                        8.2.2
  13931.  
  13932. 12.3.5    Matching Rules for Formal Access Types
  13933.  
  13934. 12.3.6    Matching Rules for Formal Subprograms
  13935.  
  13936. 12.4      Example of a Generic Package
  13937.  
  13938. 13.       Representation Clauses and 
  13939.         Implementation-Dependent Features                     4.1.4, 7.6 
  13940.  
  13941. 13.1      Representation Clauses                                       7.6.1
  13942.  
  13943. 13.2      Length Clauses                                        5.4.3, 7.6.1
  13944.  
  13945. 13.3      Enumeration Representation Clauses                    3.4.2, 7.6.1 
  13946.  
  13947. 13.4      Record Representation Clauses                         2.1.2, 7.6.1 
  13948.  
  13949. 13.5      Address Clauses                                              5.9.4
  13950.  
  13951. 13.5.1    Interrupts                                            4.1.7, 5.9.4
  13952.  
  13953. 13.6      Change of Representation                                     7.6.1
  13954.  
  13955. 13.7      The Package System                                           7.6.2
  13956.  
  13957. 13.7.1    System-Dependent Named Numbers                               7.4.3
  13958.  
  13959. 13.7.2    Representation Attributes                                    7.3.1
  13960.  
  13961. 13.7.3    Representation Attributes of Real Types                      7.2.3
  13962.  
  13963. 13.8      Machine Code Insertions                               7.1.5, 7.6.3
  13964.  
  13965. 13.9      Interface to Other Languages            5.9.3, 7.1.5, 7.6.4, 7.6.7 
  13966.  
  13967. 13.10     Unchecked Programming            
  13968.  
  13969. 13.10.1   Unchecked Storage Deallocation                 5.4.3, 5.9.2, 7.6.6 
  13970.  
  13971. 13.10.2   Unchecked Type Conversions                            5.9.1, 7.6.7 
  13972.  
  13973. 14.       Input-Output                                                   7.7
  13974.  
  13975. 14.1      External Files and File Objects
  13976.  
  13977. 14.2      Sequential and Direct Files
  13978.  
  13979. 14.2.1    File Management                                       7.7.1, 7.7.2
  13980.  
  13981. 14.2.2    Sequential Input-Output                               5.9.7, 7.7.3
  13982.  
  13983. 14.2.3    Specification of the Package Sequential_IO
  13984.  
  13985. 14.2.4    Direct Input-Output                            5.9.7, 7.7.1, 7.7.3
  13986.  
  13987. 14.2.5    Specification of the Package Direct_IO
  13988.  
  13989. 14.3      Text Input-Output                                            4.2.2
  13990.  
  13991. 14.3.1    File Management                                              7.7.2
  13992.  
  13993. 14.3.2    Default Input and Output Files
  13994.  
  13995. 14.3.3    Specification of Line and Page Lengths
  13996.  
  13997. 14.3.4    Operations on Columns, Lines, and Pages
  13998.  
  13999. 14.3.5    Get and Put Procedures
  14000.  
  14001. 14.3.6    Input-Output of Characters and Strings
  14002.  
  14003. 14.3.7    Input-Output for Integer Types
  14004.  
  14005. 14.3.8    Input-Output for Real Types
  14006.  
  14007. 14.3.9    Input-Output for Enumeration Types
  14008.  
  14009. 14.3.10   Specification of the Package Text_IO                  3.2.2, 4.2.2 
  14010.  
  14011. 14.4      Exceptions in Input-Output
  14012.  
  14013. 14.5      Specification of the Package IO_Exceptions
  14014.  
  14015. 14.6      Low Level Input-Output                                       7.7.4
  14016.       
  14017. 14.7      Example of Input-Output
  14018.  
  14019. Annexes
  14020.  
  14021. A.        Predefined Language Attributes         3.2.5, 3.4.2, 5.3.3, 5.5.1,
  14022.                              5.5.2, 6.2.3, 8.2.4
  14023.  
  14024. B.        Predefined Language Pragmas            4.1.4, 5.9.5, 6.1.4, 6.2.4,
  14025.                           7.4.5, 7.4.7, 7.6.4, 9.1.1
  14026.        
  14027.  
  14028. C.        Predefined Language Environment               3.4.1, 5.7.1, 6.1.5,
  14029.                     7.1.1, 7.1.6, 7.2.1, 7.5.1, 7.5.2, 7.6.3
  14030.  
  14031. Appendices
  14032.  
  14033. D.        Glossary
  14034.  
  14035. E.        Syntax Summary
  14036.  
  14037. F.        Implementation-Dependent Characteristics             4.1.1, 5.4.1,
  14038.                       7.1.1, 7.1.2, 7.1.3, 7.1.5, 7.1.6, 
  14039.                  7.2.1, 7.2.4, 7.4.3, 7.6.2, 7.6.3, 7.6.5, 7.6.8
  14040.        
  14041.  
  14042.  
  14043. REFERENCES
  14044.  
  14045.  
  14046.  
  14047.  
  14048.  
  14049.  
  14050. AIRMICS
  14051. 1990
  14052.  
  14053. Software Reuse Guidelines, ASQB-GI-90-015.  U.S. Army Institute for Research
  14054. in Management Information, Communications, and Computer Sciences.
  14055.  
  14056. Anderson, T. and R.W. Witty
  14057. 1978
  14058.  
  14059. Safe Programming. BIT (Tidscrift Nordisk for Informations behandling) 18:1-8.
  14060.  
  14061. ARTEWG
  14062. 1986
  14063.  
  14064. Catalogue of Ada Runtime Implementation Dependencies, draft version. 
  14065. Association for Computing Machinery, Special Interest Group for Ada, Ada 
  14066. Run-Time Environments Working Group.
  14067.  
  14068. Baker, Henry G.
  14069. 1991
  14070.  
  14071. "A Heavy Thought..." Ada Letters. 11,2:45.
  14072.  
  14073. Barnes, J.G.P. 
  14074. 1989
  14075.  
  14076. Programming in Ada. third edition. Reading, MA.: Addison-Wesley.
  14077.  
  14078. Booch, G. 
  14079. 1986
  14080.  
  14081. Software Engineering with Ada. second edition. Menlo Park, CA: The 
  14082. Benjamin/Cummings Publishing Company, Inc.
  14083.  
  14084. 1987
  14085.  
  14086. Software Components with Ada - Structures, Tools and Subsystems. Menlo Park, 
  14087. California: The Benjamin/Cummings Publishing Company, Inc.
  14088.  
  14089. CECOM
  14090. 1989
  14091.  
  14092. CECOM "Final Report -- Catalogue of Ada Runtime Implementation Dependencies,"
  14093. CIN; C02092JNB0001. 
  14094.  
  14095. Charette, R.N. 
  14096. 1986
  14097.  
  14098. Software Engineering Environments Concepts and Technology. Intertext 
  14099. Publications Inc. New York: McGraw-Hill Inc.
  14100.  
  14101. Cohen, N.H. 
  14102. 1986
  14103.  
  14104. Ada as a Second Language. New York: McGraw-Hill Inc.
  14105.  
  14106. Conti, R.A. 
  14107. 1987
  14108.  
  14109. Critical Run-Time Design Tradeoffs in an Ada Implementation. Proceedings of
  14110. the Joint Ada Conference, Fifth National Conference on Ada Technology and
  14111. Washington Ada Symposium. pp. 486-495.
  14112.  
  14113. Department of Defense
  14114. 1983
  14115.  
  14116. Reference Manual for the Ada Programming Language. ANSI/MIL-STD-1815A. 
  14117.  
  14118. Edwards, S.
  14119. 1990
  14120.  
  14121. An Approach for Constructing Reusable Software Components in Ada, IDA Paper 
  14122. P-2378.  Institute for Defense Analyses.
  14123.  
  14124. Foreman, J. and 
  14125. J. Goodenough
  14126. 1987
  14127.  
  14128. Ada Adoption Handbook: A Program Manager's Guide. Version 1.0, CMU/SEI-87-TR-9 
  14129. ESD-TR-87-110. Software Engineering Institute.
  14130.  
  14131. Gonzalez, Dean W.
  14132. 1991
  14133.  
  14134. "`=' Considered Harmful," Ada Letters. 11,2:56.
  14135.  
  14136. Goodenough, J., and 
  14137. L. Sha
  14138. 1988
  14139.  
  14140. The Priority Ceiling Protocol: A Method for Minimizing the Blocking of High 
  14141. Priority Ada Tasks, Tech. Rep. SEI-SSR-4. Software Engineering Institute.
  14142.  
  14143. Griest
  14144. 1989
  14145.  
  14146. "Limitations on the Portability of Real Time Ada Programs," Proceedings of the
  14147. 1989 Tri-Ada conference, Tom Griest.
  14148.  
  14149. Honeywell
  14150. 1986
  14151.  
  14152. A Guidebook for Writing Reusable Source Code in Ada. Corporate Systems 
  14153. Development Division. Version 1.1. CSC-86-3:8213.
  14154.  
  14155. IEEE Dictionary
  14156. 1984
  14157.  
  14158. IEEE Standard Dictionary of Electrical and Electronics Terms.  ANSI/IEEE Std 
  14159. 100-1984.
  14160.  
  14161. MacLaren, L. 
  14162. 1980
  14163.  
  14164. Evolving Toward Ada in Real Time Systems. ACM Sigplan Notices. 15(11):146-155.
  14165.  
  14166. Matthews, E.R. 
  14167. 1987
  14168.  
  14169. Observations on the Portability of Ada I/O. ACM Ada Letters. VII(5):100-103.
  14170.  
  14171. Melliar-Smith, P.M. and B. Randell
  14172. 1987
  14173.  
  14174. Software Reliability: The Role of Programmed Exception Handling. ACM Sigplan 
  14175. Notices. 12(3):95-100.
  14176.  
  14177. NASA
  14178. 1987
  14179.  
  14180. Ada Style Guide. Version 1.1, SEL-87-002. Goddard Space Flight Center: 
  14181. Greenbelt, MD 20771.
  14182.  
  14183. NASA
  14184. 1992
  14185.  
  14186. Ada Efficiency Guide.  Technical Note 552-FDD-91/068R0UD0.  NASA,  Goddard 
  14187. Space Flight Center: Greenbelt, MD 20771.
  14188.  
  14189. Nissen, J. and P. Wallis 1984
  14190.  
  14191. Portability and Style in Ada. Cambridge University Press.
  14192.  
  14193. Pappas, F. 
  14194. 1985
  14195.  
  14196. Ada Portability Guidelines. DTIC/NTIS #AD-A160 390.
  14197.  
  14198. Pyle, I.C. 
  14199. 1985
  14200.  
  14201. The Ada Programming Language. second edition. UK.: Prentice-Hall International.
  14202.  
  14203. Rosen, J. P. 
  14204. 1987
  14205.  
  14206. In Defense of the `Use' Clause. ACM Ada Letters. VII(7):77-81.
  14207.  
  14208. Ross, D.
  14209. 1989
  14210.  
  14211. The Form of a Passive Iterator. ACM Ada Letters. IX(2):102-105.
  14212.  
  14213. Schneiderman, B. 
  14214. 1986
  14215.  
  14216. Empirical Studies of Programmers: The Territory, Paths and Destinations. 
  14217. Empirical Studies of Programmers. ed. E. Soloway and S. Iyengar. pp. 1-12. 
  14218. Norwood, NJ: Ablex Publishing Corp.
  14219.  
  14220. Soloway, E., J. Pinto, 
  14221. S. Fertig, S. Letovsky, 
  14222. R. Lampert, D. Littman, 
  14223. and K. Ewing.
  14224. 1986.
  14225.  
  14226. Studying Software Documentation From A Cognitive Perspective: A Status Report. 
  14227. Proceedings of the Eleventh Annual Software Engineering Workshop. Report 
  14228. SEL-86-006, Software Engineering Laboratory. Greenbelt, MD:NASA Goddard Space 
  14229. Flight Center.
  14230.  
  14231. United Technologies 
  14232. 1987
  14233.  
  14234. CENC Programmer's Guide. Appendix A Ada Programming Standards.
  14235.  
  14236. Volz, R.A., Mudge, Naylor and Mayer. 
  14237. 1985
  14238.  
  14239. Some Problems in Distributing Real-time Ada Programs Across Machines. Ada in 
  14240. Use, Proceedings of the Ada International Conference. pp. 14-16. Paris.
  14241.  
  14242. Wheeler, David A.
  14243. 1992
  14244.  
  14245. Analysis and Guidelines for Reusable Ada Software. IDA Paper P-2765.
  14246. Alexandria, Virginia:Institute for Defense Analyses.
  14247.  
  14248.  
  14249.  
  14250. BIBLIOGRAPHY
  14251.  
  14252.  
  14253.  
  14254.  
  14255. ACVC (Ada Compiler Validation Capability). Ada Validation Facility, ASD/SIOL. 
  14256. Wright-Patterson Air Force Base, OH.
  14257.  
  14258. AIRMICS. 1990. Software Reuse Guidelines, ASQB-GI-90-015.  U.S. Army Institute 
  14259. for Research in Management Information, Communications, and Computer Sciences.
  14260.  
  14261. Anderson, T. and R. W. Witty. 1978. Safe Programming. BIT (Tidscrift Nordisk 
  14262. for Informations behandling) 18:1-8.
  14263.  
  14264. ARTEWG. November 5, 1986. Catalogue of Ada Runtime Implementation
  14265. Dependencies, draft version. Association for Computing Machinery, Special
  14266. Interest Group for Ada, Ada Run-Time Environments Working Group.
  14267.  
  14268. Bardin, Thompson. Jan-Feb 1988. Composable Ada Software Components and the
  14269. Re-Export Paradigm. ACM Ada Letters. VIII(1):58-79.
  14270.  
  14271. Bardin, Thompson. March-April 1988. Using the Re-Export Paradigm to Build
  14272. Composable Ada Software Components. ACM Ada Letters. VIII(2):39-54.
  14273.  
  14274. Barnes, J. G. P. 1989. Programming in Ada. third edition. Reading, MA.: 
  14275. Addison-Wesley.
  14276.  
  14277. Booch, G. 1987. Software Components with Ada - Structures, Tools and
  14278. Subsystems. Menlo Park, CA.: The Benjamin/Cummings Publishing Company, Inc.
  14279.  
  14280. Booch, G. 1986. Software Engineering with Ada. second edition. Menlo Park,
  14281. CA.: The Benjamin/Cummings Publishing Company, Inc.
  14282.  
  14283. Brooks, F. B. 1975. The Mythical Man-Month. Essays on Software Engineering.
  14284. Reading, MA:Addison-Wesley.
  14285.  
  14286. CECOM. 1989. CECOM "Final Report -- Catalogue of Ada Runtime Implementation
  14287. Dependencies," CIN; C02092JNB0001.
  14288.  
  14289. Charette, R. N. 1986. Software Engineering Environments Concepts and 
  14290. Technology. Intertext Publications Inc. New York: McGraw-Hill Inc.
  14291.  
  14292. Cohen, N. H. 1986. Ada as a Second Language. New York: McGraw-Hill Inc.
  14293.  
  14294. Conti, R. A. March 1987. Critical Run-Time Design Tradeoffs in an Ada
  14295. Implementation. Proceedings of the Joint Ada Conference, Fifth National 
  14296. Conference on Ada Technology and Washington Ada Symposium. pp. 486-495.
  14297.  
  14298. Cristian, F. March 1984. Correct and Robust Programs. IEEE Transactions on 
  14299. Software Engineering. SE-10(2):163-174.
  14300.  
  14301. Department of Defense, Ada Joint Program Office. 1984. Rationale for the
  14302. Design of the Ada Programming Language.
  14303.  
  14304. Department of Defense, Ada Joint Program Office. January 1983. Reference
  14305. Manual for the Ada Programming Language. ANSI/MIL-STD-1815A.
  14306.  
  14307. Edwards, S.  1990. An Approach for Constructing Reusable Software Components
  14308. in Ada, IDA Paper P-2378.  Institute for Defense Analyses.
  14309.  
  14310. Foreman, J. and J. Goodenough. May 1987. Ada Adoption Handbook: A Program 
  14311. Manager's Guide. Version 1.0, CMU/SEI-87-TR-9 ESD-TR-87-110. Software 
  14312. Engineering Institute.
  14313.  
  14314. Gary, B. and D. Pokrass. 1985, Understanding Ada A Software Engineering 
  14315. Approach. John Wiley & Sons.
  14316.  
  14317. Goodenough, J. B. March 1986. A Sample of Ada Programmer Errors. Unpublished 
  14318. draft resident in the Ada Repository under file name 
  14319. PD2:<ADA.EDUCATION>PROGERRS.DOC.2.
  14320.  
  14321. Herr, C. S. August 1987. Compiler Validation and Reusable Software. St. Louis: 
  14322. a Report from the CAMP Project, McDonnell Douglas Astronautics Company.
  14323.  
  14324. International Workshop on Real-Time Ada Issues. 1987. ACM Ada Letters. VII(6).
  14325. Mortonhampstead, Devon, U.K.
  14326.  
  14327. International Workshop on Real-Time Ada Issues II. 1988. ACM Ada Letters.
  14328. VIII(6). Mortonhampstead, Devon, U.K.
  14329.  
  14330. Kernighan, B. and P. J. Plauger, 1978. The Elements of Programming Style. New 
  14331. York: McGraw-Hill, Inc.
  14332.  
  14333. Matthews, E. R. September, October 1987. Observations on the Portability of
  14334. Ada I/O. ACM Ada Letters. VII(5):100-103.
  14335.  
  14336. MacLaren, L. November 1980. Evolving Toward Ada in Real Time Systems. ACM 
  14337. Sigplan Notices. 15(11):146-155.
  14338.  
  14339. Melliar-Smith, P. M. and B. Randell. March 1987. Software Reliability: The Role
  14340. of Programmed Exception Handling. ACM Sigplan Notices. 12(3):95-100 .
  14341.  
  14342. Mowday, B. L. and E. Normand. November 1986. Ada Programming Standards.
  14343. General Dynamics Data Systems Division Departmental Instruction 414.717.
  14344.  
  14345. NASA. May 1987. Ada Style Guide. Version 1.1, SEL-87-002. Goddard Space Flight 
  14346. Center: Greenbelt, MD 20771.
  14347.  
  14348. NASA. 1992. Ada Efficiency Guide.  Technical Note 552-FDD-91/068R0UD0.  NASA,  
  14349. Goddard Space Flight Center: Greenbelt, MD 20771.
  14350.  
  14351. Nissen, J. C. D., P. Wallis, B. A., Wichmann, et al. 1982. Ada-Europe
  14352. Guidelines for the Portability of Ada Programs. ACM Ada Letters. I(3):44-61.
  14353.  
  14354. Nissen, J. and P. Wallis. 1984. Portability and Style in Ada. Cambridge 
  14355. University Press.
  14356.  
  14357. Pappas, F. March 1985. Ada Portability Guidelines. DTIC/NTIS #AD-A160 390.
  14358.  
  14359. Pyle, I. C. 1985. The Ada Programming Language. second edition. 
  14360. UK:Prentice-Hall International.
  14361.  
  14362. Rosen, J. P. November, December 1987. In Defense of the `Use' Clause. ACM Ada 
  14363. Letters. VII(7):77-81.
  14364.  
  14365. Ross, D. March-April 1989. The Form of a Passive Iterator. ACM Ada Letters.
  14366. IX(2):102-105.
  14367.  
  14368. Rymer, J. and T. McKeever. September 1986. The FSD Ada Style Guide. IBM
  14369. Federal Systems Division Ada Coordinating Group.
  14370.  
  14371. Schneiderman, B. 1986. Empirical Studies of Programmers: The Territory, Paths 
  14372. and Destinations. Empirical Studies of Programmers. ed. E. Soloway and S. 
  14373. Iyengar. pp. 1-12. Norwood, NJ: Ablex Publishing Corp.
  14374.  
  14375. SofTech Inc. December 1985. ISEC Reusability Guidelines. Report 3285-4-247/2. 
  14376. Also US Army Information Systems Engineering Command. Waltham MA.
  14377.  
  14378. Soloway, E., J. Pinto, S. Fertig, S. Letovsky, R. Lampert, D. Littman, K. 
  14379. Ewing. December 1986. Studying Software Documentation From A Cognitive 
  14380. Perspective: A Status Report. Proceedings of the Eleventh Annual Software 
  14381. Engineering Workshop. Report SEL-86-006, Software Engineering Laboratory. 
  14382. Greenbelt, MD:NASA Goddard Space Flight Center.
  14383.  
  14384. Stark M. and E. Seidewitz. March 1987. Towards A General Object-Oriented Ada
  14385. Lifecycle. In Proceedings of the Joint Ada Conference. Fifth National 
  14386. Conference on Ada Technology and Washington Ada Symposium. 213-222.
  14387.  
  14388. St.Dennis, R. May 1986. A Guidebook for Writing Reusable Source Code in Ada 
  14389. -Version 1.1. Report CSC-86-3:8213. Golden Valley, MN: Honeywell Corporate 
  14390. Systems Development Division.
  14391.  
  14392. United Technologies. February 9, 1987. CENC Programmer's Guide. Appendix A Ada 
  14393. Programming Standards.
  14394.  
  14395. VanNeste, K.F. January/February 1986. Ada Coding Standards and Conventions.
  14396. ACM Ada Letters. VI(1):41-48.
  14397.  
  14398. Volz, R. A., Mudge, Naylor and Mayer. May 1985. Some Problems in Distributing 
  14399. Real-time Ada Programs Across Machines. Ada in Use, Proceedings of the Ada
  14400. International Conference. pp. 14-16. Paris.
  14401.  
  14402. Wheeler, David A. August 1992. Analysis and Guidelines for Reusable Ada 
  14403. Software. IDA Paper P-2765. Alexandria, Virginia:Institute for Defense
  14404. Analyses.
  14405.  
  14406.  
  14407.  
  14408. INDEX
  14409.  
  14410.  
  14411.  
  14412.  
  14413.  
  14414.  
  14415. Symbols
  14416.  
  14417. 'Base, 63
  14418.  
  14419. 'Callable, 99
  14420.  
  14421. 'Constrained, 63
  14422.  
  14423. 'Count, 99
  14424.  
  14425. 'First, 66, 67
  14426.  
  14427. 'Image, 36
  14428.  
  14429. 'Last, 66, 67
  14430.  
  14431. 'Length, 67
  14432.  
  14433. 'Pos, 36
  14434.  
  14435. 'Pred, 36
  14436.  
  14437. 'Range, 67
  14438.  
  14439. 'Size, 63
  14440.  
  14441. 'Storage_Size, 116
  14442.  
  14443. 'Succ, 36
  14444.  
  14445. 'Terminated, 99, 105
  14446.  
  14447. 'Val, 36
  14448.  
  14449. 'Value, 36
  14450.  
  14451.  
  14452.  
  14453. A
  14454.  
  14455. abbreviation, 19, 20
  14456.   capitalization, 18
  14457.   renames clause, 79
  14458.   reusability, 129
  14459.  
  14460. abnormal termination, 106
  14461.  
  14462. abort
  14463.   affects 'Count, 100
  14464.   dynamic task, 94
  14465.   portability, 118
  14466.   statement, 106
  14467.  
  14468. abstract data, shared, 92
  14469.  
  14470. abstract data object, 139
  14471.  
  14472. abstract data type, 44, 139
  14473.  
  14474. abstract state machine, 139
  14475.  
  14476. abstraction, 47, 83
  14477.   affect on naming, 128
  14478.   complete functionality, 136
  14479.   data modeling, 63
  14480.   enhanced by subprogram, 42
  14481.   includes exception, 51
  14482.   name, 22
  14483.   protect with exception handler, 82
  14484.   supported, 41
  14485.   using constrained subtype, 72
  14486.   using nested record, 65
  14487.   using private type, 63
  14488.   using types, 61
  14489.  
  14490. accept
  14491.   blocking, 96
  14492.   causing deadlock, 105
  14493.   closed, 97
  14494.   end statement, 57
  14495.   indentation, 8
  14496.   minimize, 103
  14497.   rendezvous, 96
  14498.  
  14499. access, 65
  14500.   affects equality, 80
  14501.   I/O portability, 123
  14502.   portability, 121
  14503.  
  14504. access function, 45
  14505.  
  14506. accuracy
  14507.   floating point, 114
  14508.   fraction, 18
  14509.   greater, 113
  14510.   of constant, 115
  14511.   of relational expression, 69
  14512.   portability, 115
  14513.  
  14514. acronym, capitalization, 18
  14515.  
  14516. active iterator, 142
  14517.  
  14518. actual parameter, 58
  14519.   anonymous, 62
  14520.  
  14521. adaptability, 136
  14522.  
  14523. address clause, 85
  14524.  
  14525. adjective, for boolean object, 21
  14526.  
  14527. aggregate, 77
  14528.   function calls in, 43
  14529.  
  14530. algorithm
  14531.   comment in header, 29
  14532.   concurrent, 45
  14533.   encapsulated in generic, 137
  14534.   portability, 120
  14535.  
  14536. alias
  14537.   of dynamic data, 65
  14538.   of dynamic task, 94
  14539.   using address clause, 85
  14540.  
  14541. alignment
  14542.   and nesting, 70
  14543.   declaration, 10
  14544.   parameter modes, 11
  14545.   vertical, 5, 9, 10, 11
  14546.  
  14547. allocate
  14548.   dynamic data, 65
  14549.   dynamic task, 93
  14550.  
  14551. ambiguous, use clause, 78
  14552.  
  14553. anonymous type, 62
  14554.   task, 92
  14555.  
  14556. anticipated change
  14557.   adaptability, 136
  14558.   anonymous task, 93
  14559.   comment in header, 29
  14560.   encapsulate, 44
  14561.   parameter mode, 60
  14562.  
  14563. apostrophe, spacing, 6
  14564.  
  14565. application domain
  14566.   abbreviation, 19
  14567.   abbreviation affects reusability, 129
  14568.  
  14569. application specific, literal, 24
  14570.  
  14571. application-independent, name, 128
  14572.  
  14573. array
  14574.   anonymous type, 62
  14575.   attribute, 67
  14576.   function calls in initialization, 43
  14577.   parallel, do not use, 64
  14578.   parameter passing, 85, 131
  14579.   performance, 154
  14580.   range, 67
  14581.   slice, 71
  14582.   unconstrained, 131
  14583.  
  14584. assignment
  14585.   for private type, 63
  14586.   import for limited type, 145
  14587.   reduced by aggregate, 77
  14588.  
  14589. assumption, 131
  14590.   documented through generic parameter, 146
  14591.  
  14592. asynchronous
  14593.   'Count, 99
  14594.   entity, 91
  14595.  
  14596. attribute
  14597.   'Base, 63
  14598.   'Callable, 99
  14599.   'Constrained, 63
  14600.   'Count, 99
  14601.   'First, 66, 67
  14602.   'Image, 36
  14603.   'Last, 66, 67
  14604.   'Length, 67
  14605.   'Pos, 36
  14606.   'Pred, 36
  14607.   'Range, 67
  14608.   'Size, 63
  14609.   'Storage_Size, 116
  14610.   'Succ, 36
  14611.   'Terminated, 99
  14612.   'Val, 36
  14613.   'Value, 36
  14614.   implementation-defined, 121
  14615.   in generic, 132
  14616.  
  14617.  
  14618.  
  14619. B
  14620.  
  14621. binary operator, spacing, 5
  14622.  
  14623. binding, 47
  14624.  
  14625. blank lines, 12
  14626.   for goto statement, 75
  14627.   for label, 75
  14628.   return statement, 75
  14629.  
  14630. block
  14631.   indentation, 7
  14632.   localizing exception, 82
  14633.   marker comment, 34, 35
  14634.   name, 56
  14635.   nesting, 56
  14636.   performance, 154
  14637.   statement, 76
  14638.   to minimize suppress, 85
  14639.   use clause, 78
  14640.  
  14641. blocking
  14642.   not busy waiting, 96
  14643.   with priority, 95
  14644.  
  14645. body
  14646.   comment, 29
  14647.   end statement, 57
  14648.   header, as pagination, 13
  14649.   hide interface to foreign code, 85
  14650.   hide Unchecked_Conversion, 83
  14651.   name repeated in begin, 34
  14652.   task, 106
  14653.  
  14654. boolean
  14655.   function, name, 22
  14656.   object, name, 21
  14657.  
  14658. boundary value, 61
  14659.  
  14660. busy wait, 95
  14661.   created with priorities, 103
  14662.   portability, 117
  14663.  
  14664.  
  14665.  
  14666. C
  14667.  
  14668. Calendar, portability, 117
  14669.  
  14670. capitalization, 18
  14671.   in numeric literal, 17
  14672.  
  14673. case statement, 71
  14674.   indentation, 7
  14675.   marker comment, 34
  14676.   nesting, 70
  14677.   use constrained subtype, 72
  14678.  
  14679. clause
  14680.   address, 85
  14681.   context
  14682.     minimize, 46
  14683.     visibility, 47
  14684.   length, for dynamic data, 65
  14685.   renames, 79
  14686.   representation, 116, 119, 120
  14687.     instead of enumeration, 36
  14688.   use, 78, 79
  14689.  
  14690. closing file, portability, 123
  14691.  
  14692. code, formatting, 5
  14693.  
  14694. cohesion, 44
  14695.  
  14696. colon
  14697.   alignment, 10, 12
  14698.   spacing, 6
  14699.  
  14700. comma, spacing, 6
  14701.  
  14702. comment, 17, 24
  14703.   body header, 29
  14704.   data, 30
  14705.   distinct from code, 33
  14706.   do not repeat, 30
  14707.   exception, 30
  14708.   exception handler for other, 82
  14709.   header, 25
  14710.     file, 26
  14711.     for group of routines, 28
  14712.     purpose, 28
  14713.     when to omit, 30
  14714.   label, 75
  14715.   machine code insert, 120
  14716.   marker, 34
  14717.   minimize, 24
  14718.   numerical analysis, 115
  14719.   program specification, 26
  14720.   reduced by naming, 20, 24, 56, 57, 58
  14721.   reduced by static expression, 24
  14722.   return statement, 75
  14723.   statement, 32
  14724.   tasking implementation, 49
  14725.   to document portability, 111
  14726.   trailing, alignment, 10
  14727.   type, 30
  14728.  
  14729. communication, 96
  14730.   complexity, 103
  14731.   using shared variable, 101
  14732.  
  14733. compilation
  14734.   affected by Inline, 153
  14735.   conditional, 149
  14736.   separate, 41
  14737.  
  14738. complex communication, 103
  14739.  
  14740. complex data, comment, 30
  14741.  
  14742. concurrency, 91
  14743.   See also task
  14744.   affects exception behavior, 81
  14745.  
  14746. concurrent algorithm, 45, 91
  14747.  
  14748. conditional compilation, 149
  14749.  
  14750. conditional entry
  14751.   call, 50, 102
  14752.   indentation, 8
  14753.  
  14754. conditional expression, in while loop, 72
  14755.  
  14756. configuration control, 44
  14757.  
  14758. constant, 23
  14759.   declaration, alignment, 10
  14760.   in static expression, 131
  14761.   to avoid use clause, 79
  14762.   to reduce nesting, 70
  14763.   type of, 24
  14764.  
  14765. constraint, 36, 60
  14766.  
  14767. constraint check
  14768.   for generic formal, 133
  14769.   performance, 155
  14770.  
  14771. Constraint_Error, portability, 119
  14772.  
  14773. context
  14774.   dependency, 46
  14775.   of exceptions, 50
  14776.   to shorten names, 20
  14777.  
  14778. context clause
  14779.   generic needs elaboration, 148
  14780.   indentation, 8
  14781.   minimize, 46
  14782.   per line, 14
  14783.   reduced using generic parameter, 147
  14784.   visibility, 47
  14785.  
  14786. continuation condition, for while loop, 72
  14787.  
  14788. continuation line, indentation, 6, 7, 9
  14789.  
  14790. conversion
  14791.   loss of precision, 115
  14792.   of a private type, 63
  14793.   rational fraction, 18
  14794.   type, 61
  14795.   unchecked, 83, 122
  14796.  
  14797. copyright notice, 26
  14798.  
  14799. coupling
  14800.   data, 45
  14801.   due to pragma, 148
  14802.   reduced using generic parameter, 147
  14803.  
  14804. cyclic activity, 45
  14805.  
  14806. cyclic executive, termination, 106
  14807.  
  14808.  
  14809.  
  14810. D
  14811.  
  14812. dangling reference, 65
  14813.  
  14814. data
  14815.   abstract type, 139
  14816.   comment, 30
  14817.   coupling, 45
  14818.   dynamic, 65
  14819.   grouped in package, 44
  14820.   in algorithm, 137
  14821.   iterator for complex, 142
  14822.   protected, 101
  14823.   representation, 120
  14824.   shared, 45, 100
  14825.   structure, 63
  14826.   Unchecked_Conversion, 83
  14827.  
  14828. data-driven program, 150
  14829.  
  14830. dead code, 149
  14831.  
  14832. deadlock, 49
  14833.   eliminate, 95
  14834.  
  14835. deallocation, 65
  14836.  
  14837. declaration
  14838.   alignment, 10
  14839.   anonymous task, 93
  14840.   array size, 131
  14841.   blank lines, 12
  14842.   constant, 23
  14843.   constrained subtype, 72
  14844.   digits, 113
  14845.   exception, 50
  14846.   floating point, 114
  14847.   function call in, 85
  14848.   grouping, 44
  14849.   hiding, 79
  14850.   minimize, 46
  14851.   named number, 23
  14852.   per line, 14
  14853.   range, 113
  14854.   record, for heterogeneous data, 63
  14855.   renames, 20, 78, 79
  14856.   type, 20, 35
  14857.   variable, 45
  14858.   within block, 76
  14859.  
  14860. default mode, 60
  14861.  
  14862. default parameter, 59
  14863.  
  14864. delay
  14865.   drift, 96
  14866.   in selective wait, 102
  14867.   inaccurate, 95
  14868.   portability, 117
  14869.   statement, 95
  14870.   to avoid deadlock, 105
  14871.  
  14872. delimiter, spacing, 5
  14873.  
  14874. dependency
  14875.   affects reusability, 147
  14876.   comment about, 27
  14877.   context, 46
  14878.   reduced using generic parameter, 148
  14879.  
  14880. derived type, 35, 60
  14881.  
  14882. design
  14883.   for reusability, 127
  14884.   impact of concurrency, 91
  14885.   impact of typing, 36
  14886.   impact on nesting, 70
  14887.   uses data representation, 120
  14888.  
  14889. digits declaration, 113
  14890.  
  14891. Direct_IO, 86
  14892.   import private type, 147
  14893.  
  14894. discrete, affects equality, 80
  14895.  
  14896. discriminant, of a private type, 63
  14897.  
  14898. documentation
  14899.   exception in abstraction, 50
  14900.   generic formal parameter, 130
  14901.   hidden task, 134
  14902.   infinite loop, 75
  14903.   invalid state, 135
  14904.   object value, 21
  14905.   of assumption, 131
  14906.   of implementation dependency, 112
  14907.   of iterator behavior, 142
  14908.   of machine code, 120
  14909.   of numerical analysis, 115
  14910.   of system call, 122
  14911.   portability, 111
  14912.   table-driven code, 151
  14913.   using named number, 131
  14914.  
  14915. drift, delay, 96
  14916.  
  14917. Duration, 110
  14918.   portability, 117
  14919.  
  14920. dynamic data, 65
  14921.   adaptability, 136
  14922.   deallocation, 84
  14923.  
  14924. dynamic storage, 116
  14925.  
  14926. dynamic task, 93
  14927.  
  14928.  
  14929.  
  14930. E
  14931.  
  14932. Elaborate, 86
  14933.   when to use, 148
  14934.  
  14935. elaboration, 85
  14936.   of value, 23
  14937.  
  14938. else clause
  14939.   comment, 34
  14940.   nesting, 70
  14941.  
  14942. else part
  14943.   in selective wait, 102
  14944.   open alternative, 98
  14945.   to avoid deadlock, 105
  14946.  
  14947. elsif clause, nesting, 70
  14948.  
  14949. encapsulation, 44
  14950.   implementation dependency, 112, 119
  14951.   of algorithm in generic, 137
  14952.   of synchronization code, 101
  14953.   supported, 41
  14954.  
  14955. end statement
  14956.   name, 57
  14957.   pagination, 13
  14958.  
  14959. entry
  14960.   address clause, 85
  14961.   attribute, 99
  14962.   call, 49
  14963.     avoiding Tasking_Error, 99
  14964.     named association, 58
  14965.   conditional, 50, 102
  14966.   default parameter, 59
  14967.   exceptions raised in, 50
  14968.   hiding, 49
  14969.   indentation, 8
  14970.   interrupt, 85
  14971.   minimize, 104
  14972.   minimize accepts, 103
  14973.   name, 22
  14974.   parameter list, 58
  14975.   parameter mode, 60
  14976.   queue
  14977.     'Count, 99
  14978.     not prioritized, 94
  14979.   timed, 50, 102
  14980.     affects 'Count, 100
  14981.  
  14982. enumeration
  14983.   alignment, 10, 11
  14984.   in case statement, 71
  14985.   literal, 78
  14986.   type, 36
  14987.  
  14988. equality
  14989.   for private type, 63
  14990.   import for limited type, 145
  14991.   overload operator, 80
  14992.  
  14993. erroneous execution, 83
  14994.   not portable, 109
  14995.  
  14996. error
  14997.   as an exception, 50
  14998.   unrecoverable, use exception, 51
  14999.  
  15000. evaluation order
  15001.   parenthesis, 67
  15002.   select statement, 117
  15003.  
  15004. exception, 50, 80
  15005.   avoiding, 81
  15006.   cause, 82
  15007.   comment, 27, 30
  15008.   Constraint_Error, portability, 119
  15009.   declaration, 50
  15010.   do not propagate, 50
  15011.   do not raise, 50
  15012.   handler, 50, 81, 82
  15013.     for Storage_Error, 65
  15014.     in block, 76
  15015.     in task body, 97, 106
  15016.     reusability, 134
  15017.     to avoid termination, 104
  15018.   implementation-defined, 82, 119
  15019.   in initialization, 86
  15020.   keep error separate, 51
  15021.   name, 50
  15022.   Numeric_Error, portability, 119
  15023.   part of abstraction, 51
  15024.   portability, 118
  15025.   predefined, 82, 118
  15026.   Program_Error, 97
  15027.     erroneous execution, 83
  15028.   propagation, 82, 83, 134
  15029.   reusability, 134
  15030.   Storage_Error, 65
  15031.   suppress, 85
  15032.   Tasking_Error, 97, 99
  15033.   user-defined, 82
  15034.  
  15035. execution pattern, 96
  15036.   portable, 117
  15037.  
  15038. execution speed, 153
  15039.  
  15040. exit statement, 57, 72, 73
  15041.   conditional, 69
  15042.   in loop, 72
  15043.  
  15044. export, overloading in generic, 134
  15045.  
  15046. expression, 66
  15047.   aggregate, 77
  15048.   alignment, 9, 11
  15049.   evaluation, portability, 115
  15050.   function calls in, 43
  15051.   logical, 68
  15052.   nesting, 69
  15053.   numeric, 113
  15054.   order dependency, 87
  15055.   parenthesis, 67
  15056.   relational, 68, 69
  15057.   slice, 71
  15058.   spacing, 6
  15059.   static, 23, 130
  15060.   universal_real, 115
  15061.   use named association, 58
  15062.   
  15063.  
  15064.  
  15065. F
  15066.  
  15067. family of parts, 149
  15068.  
  15069. file
  15070.   closing, 123
  15071.   header, 26
  15072.   naming conventions, 41
  15073.   organization, 41
  15074.  
  15075. finalization, complete functionality, 136
  15076.  
  15077. fixed point
  15078.   in relational expression, 69
  15079.   precision, 110
  15080.  
  15081. flag
  15082.   in complex loop, 73
  15083.   in while loop, 73
  15084.   naming, 68
  15085.  
  15086. floating point
  15087.   accuracy, 114, 115
  15088.   affects equality, 80
  15089.   arithmetic, 114
  15090.   in relational expression, 69
  15091.   model, 114, 115
  15092.   precision, 110, 114
  15093.   relational expression, 115
  15094.  
  15095. flow of control, 81
  15096.  
  15097. for loop, 72
  15098.   indentation, 7
  15099.   is bounded, 75
  15100.  
  15101. foreign code, 85
  15102.  
  15103. Form, parameter in predefined I/O, 123
  15104.  
  15105. formal parameter, 58
  15106.   anonymous, 62
  15107.   generic, 130
  15108.   name, 58
  15109.  
  15110. formatter, 6, 9, 10, 11, 12, 13, 14, 15, 17, 19
  15111.  
  15112. FORTRAN, 64
  15113.   equivalence, 85
  15114.  
  15115. fraction, 18
  15116.  
  15117. free list, 66
  15118.  
  15119. function
  15120.   access, 45
  15121.   body, indentation, 8
  15122.   call
  15123.  
  15124. in dclaration, 85
  15125.     named association, 58
  15126.     recursive, 74
  15127.     spacing, 6
  15128.   default parameter, 59
  15129.   end statement, 57
  15130.   generic, 137, 147
  15131.   Inline, 153
  15132.   interrogative, to avoid exception, 50
  15133.   name, 22
  15134.   overload, 79
  15135.   parameter list, 58
  15136.   procedure versus, 43
  15137.   return, 75
  15138.   side effect, 43
  15139.   specification, indentation, 8
  15140.   to reduce nesting, 70
  15141.  
  15142. functionality, complete, 136
  15143.  
  15144.  
  15145.  
  15146. G
  15147.  
  15148. garbage collection
  15149.   of dynamic data, 65
  15150.   Unchecked_Deallocation, 84
  15151.  
  15152. generic, 137
  15153.   abstract data object, 139
  15154.   abstract data type, 139
  15155.   instance, indentation, 8
  15156.   name, 22, 128
  15157.   named association, 58
  15158.   package, 47, 134
  15159.   parameter, 130
  15160.     accessed within task, 134
  15161.     indentation, 8
  15162.     to reduce coupling, 147
  15163.   robustness, 132
  15164.   subtype in formal, 132
  15165.   to encapsulate algorithm, 137
  15166.   when formal raise exception, 134
  15167.  
  15168. global data, access, 46
  15169.  
  15170. global effect, comment, 27
  15171.  
  15172. goto, 75
  15173.   simulated by exception, 81
  15174.  
  15175. guard
  15176.   causing Program_Error, 97
  15177.   evaluation order, 117
  15178.   nonlocal variable, 100
  15179.   referencing 'Count, 100
  15180.  
  15181. guideline, violation, 24
  15182.  
  15183.  
  15184.  
  15185. H
  15186.  
  15187. header, file, 26
  15188.  
  15189. heterogeneous data, 63
  15190.  
  15191. hidden task, 48, 134
  15192.   avoid Priority, 148
  15193.  
  15194. hiding, declarations, 79
  15195.  
  15196. horizontal spacing, 5
  15197.  
  15198.  
  15199.  
  15200. I
  15201.  
  15202. identifier
  15203.   abbreviation, 19, 129
  15204.   capitalization, 18
  15205.   constant, 23
  15206.   naming convention, 20
  15207.   numeric, 23
  15208.   object, 21
  15209.   reusability, 128
  15210.   type, 20
  15211.   use of underscore, 17
  15212.   visibility, 46
  15213.  
  15214. if statement
  15215.   avoid exit, 73
  15216.   indentation, 7
  15217.   marker comment, 34
  15218.   nesting, 70
  15219.   positive name, 68
  15220.  
  15221. immediately, undefined, 103
  15222.  
  15223. implementation
  15224.   added feature, 113
  15225.   comment in header, 29
  15226.   encapsulate decisions, 44
  15227.   hide detail, 46
  15228.  
  15229. implementation dependent, 119
  15230.   actual limit, 111
  15231.   at run time, 122
  15232.   encapsulation, 112
  15233.   global assumptions, 110
  15234.   storage specification, 116
  15235.   tentative rendezvous, 103
  15236.  
  15237. implementation-defined
  15238.   attribute, 121
  15239.   exception, 82, 119
  15240.   pragma, 121
  15241.   System constant, 120
  15242.   Unchecked_Conversion, 84
  15243.  
  15244. in, 60
  15245.   alignment, 12
  15246.  
  15247. in out, 60
  15248.   for limited type, 145
  15249.   used in generic formal, 132
  15250.  
  15251. incremental scheme, to improve performance, 155, 156
  15252.  
  15253. indentation, 6
  15254.   affects abbreviation, 20
  15255.   of declarations, 10
  15256.  
  15257. inequality, for private type, 63
  15258.  
  15259. infinite loop, 74
  15260.  
  15261. infix operator, 78, 79
  15262.  
  15263. information hiding, 41, 44
  15264.   aids adaptability, 136
  15265.   effects exception handling, 51
  15266.   enforced through visibility, 46
  15267.   using iterator, 144
  15268.   using private type, 63
  15269.  
  15270. initialization, 85
  15271.   in declaration, alignment, 10
  15272.   performance, 154
  15273.   procedure, 136
  15274.  
  15275. Inline, improves speed, 153
  15276.  
  15277. input/output
  15278.   Low_Level_IO, 123
  15279.   on access type, 123
  15280.   portability, 122
  15281.  
  15282. instantiation
  15283.   name, 22, 128
  15284.   named association, 58
  15285.   reusability, 137
  15286.  
  15287. Integer, portability, 110
  15288.  
  15289. Interface
  15290.   portability, 120
  15291.   to foreign language, 121
  15292.  
  15293. interface
  15294.   access to device, 91
  15295.   comment, 27
  15296.   implementation-defined exception, 119
  15297.   minimize, 46
  15298.   parameter list, 58
  15299.   to a device, 44, 63, 85, 123
  15300.   to device data, 120
  15301.   to foreign code, 85, 120, 121
  15302.   undocumented, 47
  15303.  
  15304. interrupt
  15305.   entry, 85
  15306.   implementation dependent, 112
  15307.   scheduling portability, 118
  15308.  
  15309. interval, delay, 96
  15310.  
  15311. iteration
  15312.   bound, 74
  15313.   using loop statement, 72
  15314.  
  15315. iterator, 142
  15316.  
  15317.  
  15318.  
  15319. L
  15320.  
  15321. label, 75
  15322.   delimiter, 6
  15323.   indentation, 7
  15324.  
  15325. late initialization, 154
  15326.  
  15327. length, line, 15
  15328.  
  15329. length clause, for dynamic data, 65
  15330.  
  15331. library
  15332.   binding, 47
  15333.   reuse, 79
  15334.   separate compilation, 41
  15335.  
  15336. limited private type, 62
  15337.   equality, 80
  15338.   I/O difficult, 147
  15339.   versus private, 145
  15340.  
  15341. line
  15342.   continuation, indentation, 6
  15343.   length, 15
  15344.   multiple, 14
  15345.   statements per, 14
  15346.  
  15347. linear independence, 24
  15348.  
  15349. literal
  15350.   avoid in generic, 132
  15351.   enumeration, 78
  15352.   linear independence of, 23
  15353.   numeric, 17, 66, 67
  15354.   self-documenting, 24
  15355.   string, 5
  15356.   use named association, 58
  15357.  
  15358. localize
  15359.   declaration, 76
  15360.   implementation dependency, 112
  15361.   scope, 78
  15362.  
  15363. logical operator, 68
  15364.  
  15365. loop, 72
  15366.   array slices, 71
  15367.   bound, 74
  15368.   busy wait, 95, 103
  15369.   conditional exit, 69
  15370.   exit, 73
  15371.     using relational expression, 69
  15372.   indentation, 7
  15373.   infinite, 74
  15374.   marker comment, 35
  15375.   name, 55, 57
  15376.   nesting, 55, 57
  15377.  
  15378. Low_Level_IO, portability, 123
  15379.  
  15380. lower case, 18
  15381.  
  15382.  
  15383.  
  15384. M
  15385.  
  15386. machine code, not portable, 120
  15387.  
  15388. machine dependency, encapsulated, 44
  15389.  
  15390. main program, 112
  15391.  
  15392. marker comment, 34
  15393.  
  15394. membership test, of a private type, 63
  15395.  
  15396. memory management
  15397.   of dynamic data, 65
  15398.   of task, 94
  15399.   Unchecked_Deallocation, 84
  15400.  
  15401. mod, performance, 155
  15402.  
  15403. mode
  15404.   alignment, 11
  15405.   explicit, 60
  15406.  
  15407. model
  15408.   floating point, 115
  15409.   task, 91
  15410.  
  15411. model interval
  15412.   affects equality, 80
  15413.   affects relational expression, 69, 116
  15414.  
  15415. modularity, 44
  15416.  
  15417. multiple return statement, 76
  15418.  
  15419. multiprocessor, 45, 92
  15420.  
  15421. mutual exclusion, and priority, 95
  15422.  
  15423.  
  15424.  
  15425. N
  15426.  
  15427. Name, parameter in predefined I/O, 123
  15428.  
  15429. name, 20
  15430.   abbreviation, 19, 129
  15431.   block, 56
  15432.   boolean, 68
  15433.   capitalization, 18
  15434.   convention, 20
  15435.   end statement, 57
  15436.   flag, 68
  15437.   formal parameter, 58
  15438.   fully qualified, 20, 79
  15439.   loop, 55, 57
  15440.   nested record, 64
  15441.   number, 23
  15442.   object, 21
  15443.   overloading, in generic, 134
  15444.   predefined, 35
  15445.   program, 22
  15446.   qualified, 47
  15447.   repeated in begin, 34
  15448.   repeated in header, 26, 29
  15449.   reusability, 128
  15450.   simple, 17
  15451.   state, 68
  15452.   subtype, 35
  15453.   type, 20, 35
  15454.   use positive form, 68
  15455.  
  15456. named association, 58, 59
  15457.   in aggregate, 77
  15458.  
  15459. named number, 23, 115, 130
  15460.   to specify priority, 149
  15461.  
  15462. negative logic, in name, 68
  15463.  
  15464. nesting, 69
  15465.   affects abbreviation, 20
  15466.   block, 56
  15467.   control structure, 70
  15468.   expression, 69
  15469.   indentation, 6
  15470.   initialization exception, 86
  15471.   loop, 55, 57
  15472.   package, 47
  15473.   record, 64
  15474.  
  15475. new, as an allocator, 65
  15476.  
  15477. non-terminating, tasks, 105
  15478.  
  15479. normal termination, 105
  15480.  
  15481. noun
  15482.   as function name, 22
  15483.   as identifier, 21
  15484.   for record component, 21
  15485.   to describe abstraction, 22
  15486.  
  15487. numeric
  15488.   conversion, 18
  15489.   encoding, 36
  15490.   expression, 113
  15491.   in relational expression, 69
  15492.   literal, 17, 66, 67
  15493.   named, 23
  15494.   type, 113
  15495.  
  15496. Numeric_Error, portability, 119
  15497.  
  15498.  
  15499.  
  15500. O
  15501.  
  15502. object
  15503.   identifier, 21
  15504.   initialization, 85
  15505.   name, 21
  15506.  
  15507. operating system, dependence, 122
  15508.  
  15509. operator
  15510.   alignment, 9, 10
  15511.   equality, 80
  15512.   infix, 78
  15513.   logical, 68
  15514.   mod, 155
  15515.   overload, 80
  15516.   precedence, 6, 67, 70
  15517.   rem, 155
  15518.   renamed, 79
  15519.   short circuit, 68
  15520.   spacing, 5
  15521.  
  15522. optimizing compiler, values not checked, 86
  15523.  
  15524. optional parameter, 58
  15525.  
  15526. order
  15527.   of arguments in aggregate, 77
  15528.   of elaboration, 149
  15529.   of evaluation, 43, 68, 87
  15530.     in expression, 67
  15531.  
  15532. others clause
  15533.   in case statement, 71
  15534.   in exception, 50, 81
  15535.   in task body, 106
  15536.  
  15537. out, 60
  15538.   alignment, 12
  15539.   not for limited type, 145
  15540.  
  15541. overload
  15542.   equality, 80
  15543.   in generic, 134
  15544.   operator, 80
  15545.   subprogram, 79
  15546.   type name, 35
  15547.   use clause, 78
  15548.  
  15549.  
  15550.  
  15551. P
  15552.  
  15553. package, 44
  15554.   abstract data type, 139
  15555.   body
  15556.     comment, 29
  15557.     file name, 41
  15558.     for different environment, 112
  15559.     hide Unchecked_Conversion, 83
  15560.     hide Unchecked_Deallocation, 84
  15561.     indentation, 8
  15562.     multiple implementation, 42
  15563.     using pragma Interface, 121
  15564.   Calendar, portability, 117
  15565.   cohesion, 44
  15566.   comment, 26
  15567.   coupling, 45
  15568.   dependency, 47
  15569.   Direct_IO, 86
  15570.   document non-portable, 111
  15571.   end statement, 57
  15572.   generic, 47, 137, 147
  15573.   implementation-defined exception, 119
  15574.   interface, 112
  15575.   Low_Level_IO, 123
  15576.   minimize interface, 46
  15577.   name, 22
  15578.   named in use clause, 78
  15579.   nested, 47
  15580.   predefined
  15581.     type name, 20
  15582.     vendor supplied feature, 113
  15583.   private, 62
  15584.   Sequential_IO, 86
  15585.   specification, 46, 47
  15586.     exception declaration, 50
  15587.     file name, 41
  15588.     indentation, 8
  15589.     pagination, 13
  15590.     portability, 112
  15591.   Standard, 35
  15592.     predefined numeric type, 113
  15593.   System
  15594.     portability, 120
  15595.     portability of Tick, 117
  15596.   Text_IO, 47
  15597.   vendor supplied, 113
  15598.  
  15599. pagination, 13, 34
  15600.  
  15601. paragraphing, 7
  15602.  
  15603. parameter
  15604.   adding to list, 59
  15605.   aggregate, 77
  15606.   alignment, 11
  15607.   anonymous, 62
  15608.   array, 131
  15609.   declaration, per line, 14
  15610.   default value, 59
  15611.   for main program, 112
  15612.   formal name, 58
  15613.   generic formal, 130
  15614.   generic reduces coupling, 147
  15615.   in predefined I/O, 123
  15616.   list, 58
  15617.   mode, 60
  15618.     alignment, 11
  15619.   name in header, 27
  15620.   named association, 58
  15621.   number, 46
  15622.   optional, 58
  15623.   passing mechanism, 84
  15624.     with exception, 135
  15625.   profile, 79
  15626.   size, 131
  15627.   unmodified with exception, 134
  15628.  
  15629. parameter type, alignment, 12
  15630.  
  15631. parenthesis, 67
  15632.   alignment, 11
  15633.   spacing, 6
  15634.   superfluous, 6
  15635.  
  15636. parser, use table-driven program, 150
  15637.  
  15638. part family, 149
  15639.  
  15640. passive iterator, 142
  15641.  
  15642. performance, 153
  15643.   access to data, 45
  15644.   comment in header, 27
  15645.   named number, 24
  15646.  
  15647. period, spacing, 6
  15648.  
  15649. periodic activity, 96
  15650.  
  15651. persistent object, 47
  15652.  
  15653. plain loop, 72
  15654.  
  15655. pointer
  15656.   See also access
  15657.   to task, 94
  15658.  
  15659. polling, 95
  15660.   portability, 117
  15661.  
  15662. portability, 15, 44, 109
  15663.   comment in header, 29
  15664.   execution pattern, 96
  15665.   of relational expression, 69
  15666.   order dependency, 87
  15667.   principles, 109
  15668.  
  15669. positional association, 59, 77
  15670.  
  15671. positive logic, naming, 68
  15672.  
  15673. pragma
  15674.   Elaborate, 86, 148
  15675.   implementation-defined, 121
  15676.   Inline, 153
  15677.   Interface
  15678.     portability, 120
  15679.     to foreign code, 121
  15680.   introduce coupling, 148
  15681.   Priority, 94, 148
  15682.     portability, 118
  15683.   Shared, 101
  15684.     portability, 118
  15685.   Suppress, 85
  15686.  
  15687. precedence of operator, 67, 70
  15688.  
  15689. precision
  15690.   fixed point, 110
  15691.   floating point, 110, 114
  15692.  
  15693. predefined
  15694.   exception
  15695.     do not raise, 50
  15696.     handle, 82
  15697.   portability, 118
  15698.   I/O parameter, 123
  15699.  
  15700. predefined type, 35
  15701.   as a name, 20
  15702.   numeric, 113
  15703.  
  15704. String index, 114
  15705.  
  15706. predicate
  15707.   as function name, 22
  15708.   for boolean object, 21
  15709.  
  15710. preemptive scheduling, 118
  15711.  
  15712. prioritized activity, 45
  15713.  
  15714. Priority, 94
  15715.   can create busy wait, 103
  15716.   not for hidden task, 148
  15717.   portability, 118
  15718.  
  15719. priority inversion, 95
  15720.  
  15721. private type, 62
  15722.   equality, 80
  15723.   for numeric type, 113
  15724.   versus limited, 145
  15725.  
  15726. problem domain, model with task, 91
  15727.  
  15728. procedure
  15729.   as main program, 112
  15730.   call
  15731.     named association, 58
  15732.     recursive, 74
  15733.   default parameter, 59
  15734.   end statement, 57
  15735.   generic, 137, 147
  15736.   Inline, 153
  15737.   name, 22
  15738.   overload, 79
  15739.   parameter list, 58
  15740.   parameter mode, 60
  15741.   return, 75
  15742.   to reduce nesting, 70
  15743.   versus function, 43
  15744.  
  15745. processor
  15746.   multiple, 92
  15747.   virtual, 92
  15748.  
  15749. program
  15750.   body, indentation, 8
  15751.   grouping, 44
  15752.   name, 22
  15753.   pagination, 13
  15754.   termination, 82, 106
  15755.   visibility, 47
  15756.  
  15757. Program_Error, 97
  15758.   erroneous execution, 83
  15759.  
  15760. project
  15761.   abbreviation, 20
  15762.   entry name, 23
  15763.  
  15764. prologues, as pagination, 13
  15765.  
  15766. propagation, 82
  15767.   exception, 83, 134
  15768.  
  15769.  
  15770.  
  15771. Q
  15772.  
  15773. qualified name, 47, 78, 79
  15774.  
  15775. queue, entry not prioritized, 95
  15776.  
  15777.  
  15778.  
  15779. R
  15780.  
  15781. race condition, 49, 105
  15782.   attribute, 99
  15783.   in tentative rendezvous, 103
  15784.   priority, 95
  15785.   with shared variable, 101
  15786.  
  15787. radix, 17
  15788.   precision, 115
  15789.  
  15790. raise statement, in abstraction, 50
  15791.  
  15792. range
  15793.   constraint, 60
  15794.   declaration, 113
  15795.   Duration, 110
  15796.   in case statement, 71
  15797.   scalar types, 35
  15798.   values, 66
  15799.  
  15800. real operand, in relational expression, 69
  15801.  
  15802. recompilation, reduced by separate file, 42
  15803.  
  15804. record
  15805.   assignment, 77
  15806.   component, name, 21
  15807.   heterogeneous data, 63
  15808.   indentation, 8
  15809.   map to device data, 63
  15810.   nesting, 64
  15811.   parameter passing, 85
  15812.   with access type component, 65
  15813.  
  15814. recursion, bound, 74
  15815.  
  15816. relational expression, 68, 69
  15817.   portability, 115
  15818.  
  15819. rem, performance, 155
  15820.  
  15821. renames clause, 20, 78, 79
  15822.   declare in block, 76
  15823.   for a type, 36
  15824.  
  15825. rendezvous
  15826.   efficient, 96
  15827.   exception during, 97
  15828.   instead of shared variable, 100
  15829.   tentative, 102
  15830.   versus shared variable, 118
  15831.   with exception handler, 104
  15832.  
  15833. repeat until, how to simulate, 73
  15834.  
  15835. representation clause
  15836.   evaluate during porting, 120
  15837.   for device data, 64
  15838.   indentation, 9
  15839.   instead of enumeration, 36
  15840.   portability, 116, 119, 120
  15841.  
  15842. reserved word, capitalization, 18
  15843.  
  15844. return statement, 75
  15845.  
  15846. reusability, 127
  15847.   library, 79
  15848.   of non-terminating program, 106
  15849.   renames clause, 79
  15850.  
  15851. robust software, 130
  15852.  
  15853. run time system, dependence, 122
  15854.  
  15855. runaway task, 106
  15856.  
  15857.  
  15858.  
  15859. S
  15860.  
  15861. safe numbers, for floating point, 114
  15862.  
  15863. safe programming, 75
  15864.  
  15865. scheduling
  15866.   algorithm
  15867.     affected by hidden task, 134
  15868.     portability, 118
  15869.   delay, 96
  15870.   task, 106
  15871.   using priority, 95
  15872.  
  15873. scientific notation, 17
  15874.  
  15875. scope
  15876.   access type, portability, 121
  15877.   exception, 50
  15878.   minimize, 47
  15879.   use clause, 78
  15880.  
  15881. select statement
  15882.   blocking, 96
  15883.   minimize, 103
  15884.   portability, 117
  15885.   to provide normal termination, 105
  15886.  
  15887. selected component, of a private type, 63
  15888.  
  15889. selective wait
  15890.   closed alternatives, 97
  15891.   efficient, 96
  15892.   indentation, 8
  15893.   with else, 102
  15894.  
  15895. semicolon, spacing, 6
  15896.  
  15897. sentinel value, 61
  15898.  
  15899. separate
  15900.   compilation, 41
  15901.   indentation, 8
  15902.   to reduce visibility, 48
  15903.  
  15904. separation of concerns, 46
  15905.  
  15906. Sequential_IO, 86
  15907.   import private type, 147
  15908.  
  15909. Shared, 101
  15910.   portability, 118
  15911.  
  15912. shared data, 45
  15913.   hidden task in generic, 134
  15914.  
  15915. shared variable, 100
  15916.   portability, 118
  15917.  
  15918. short circuit operator, 68
  15919.  
  15920. side effect, 43, 69
  15921.  
  15922. simplification heuristics, 70
  15923.  
  15924. slice, 71
  15925.  
  15926. source text, 5, 110
  15927.  
  15928. spacing, 5
  15929.   for goto statement, 75
  15930.   for label, 75
  15931.   horizontal, 5
  15932.  
  15933. specification
  15934.   comment, 26
  15935.   end statement, 57
  15936.   generic, 132
  15937.   header, as pagination, 13
  15938.   indentation, 8
  15939.   package, 46, 47
  15940.   reusable part family, 149
  15941.   task hiding, 49, 134
  15942.  
  15943. spelling, 17
  15944.   abbreviation, 19
  15945.   in comments, 25
  15946.  
  15947. Standard, 35
  15948.   predefined numeric type, 113
  15949.  
  15950. starvation, 49
  15951.  
  15952. state
  15953.   and exception, 50
  15954.   naming, 68
  15955.  
  15956. statement, 69
  15957.   abort, 106, 118
  15958.   accept, 97, 103
  15959.   block, 76
  15960.   case, 71
  15961.   comment, 32
  15962.   delay, 95, 117
  15963.   end, 57
  15964.   exit, 57, 72, 73
  15965.   goto, 75
  15966.   indentation, 6
  15967.   loop, 71
  15968.     conditional exit, 69
  15969.   marker comment, 34
  15970.   per line, 14
  15971.   return, 75
  15972.   select, 97, 103
  15973.     portability, 117
  15974.   tentative rendezvous, 102
  15975.  
  15976. static
  15977.   data, 65
  15978.   expression, 23, 130
  15979.  
  15980. Storage_Error, 65
  15981.  
  15982. String, indexed with subtype, 114
  15983.  
  15984. strong typing, 35, 41, 60
  15985.   to enforce assumption, 131
  15986.   to reduce constraint check, 155
  15987.  
  15988. subprogram, 42
  15989.   call
  15990.     named association, 58
  15991.     overhead, 43
  15992.     recursive, 74
  15993.   default parameter, 59
  15994.   document non-portable, 111
  15995.   end statement, 57
  15996.   exceptions raised in, 50
  15997.   generic, 137, 147
  15998.   grouped in package, 44
  15999.   grouping, 41
  16000.   hiding task entries, 49
  16001.   Inline, 153
  16002.   main, 112
  16003.   name, 22
  16004.   overload, 79
  16005.   overloading in generic, 134
  16006.   parameter list, 46, 58
  16007.   procedure versus function, 43
  16008.   return, 75
  16009.   to reduce nesting, 70
  16010.  
  16011. subrecord, 64
  16012.  
  16013. subtype, 35, 60
  16014.   in case statement, 72
  16015.   in generic, 132
  16016.   used as range, 66
  16017.  
  16018. subunit
  16019.   embedded, pagination, 13
  16020.   file name, 41
  16021.   indentation, 8
  16022.   minimize context, 47
  16023.   visibility, 47
  16024.  
  16025. Suppress, 85
  16026.  
  16027. symbolic, value, 23
  16028.  
  16029. synchronization, 91
  16030.   and abort statement, 106
  16031.   portability, 118
  16032.   using shared variable, 100
  16033.  
  16034. System
  16035.   portability, 120
  16036.   portability of Tick, 117
  16037.  
  16038. system, do not comment, 27
  16039.  
  16040.  
  16041.  
  16042. T
  16043.  
  16044. tab character, 7
  16045.  
  16046. table-driven program, 150
  16047.  
  16048. task, 45, 91
  16049.   abort dynamic, 94
  16050.   activation order, 117
  16051.   allocate, 93
  16052.   anonymous type, 92
  16053.   attribute, 99
  16054.   avoid termination, 104
  16055.   body
  16056.     exception handler, 106
  16057.     indentation, 8
  16058.     order, 94
  16059.   communication, 49, 96, 97
  16060.     complexity, 103
  16061.     portability, 118
  16062.   declaration, 92
  16063.   document non-portable, 111
  16064.   dynamic, 93
  16065.   end statement, 57
  16066.   hidden, 48, 134, 148
  16067.     comment in header, 27
  16068.   model, 91
  16069.   name, 22
  16070.   non-terminating, 105
  16071.   parameter passing, 85
  16072.   portability, 117
  16073.   receiving interrupt, 112
  16074.   rendezvous, 96
  16075.   runaway, 106
  16076.   scheduling, 106
  16077.     portability, 118
  16078.   specification
  16079.     indentation, 8
  16080.     pagination, 13
  16081.   synchronization, 100
  16082.     point, 118
  16083.     portability, 118
  16084.   termination, 104, 105
  16085.   type, 92
  16086.  
  16087. Tasking_Error, 97, 99
  16088.  
  16089. temporary file, portability, 123
  16090.  
  16091. tentative rendezvous, 102
  16092.  
  16093. terminate alternative, to avoid deadlock, 105
  16094.  
  16095. termination, 104
  16096.   abnormal, 106
  16097.   controlled, 82
  16098.   dynamic task, 94
  16099.   file status, 123
  16100.   normal, 105
  16101.   of loop, 73
  16102.  
  16103. Text_IO, 47
  16104.  
  16105. thread of control, 92
  16106.  
  16107. Tick, portability, 117
  16108.  
  16109. time sliced, scheduling, 118
  16110.  
  16111. timed entry, 102
  16112.   affects 'Count, 100
  16113.   call, 50
  16114.   indentation, 8
  16115.  
  16116. timing
  16117.   affected by task, 94
  16118.   execution pattern, 96
  16119.  
  16120. tool, 5, 25, 79
  16121.  
  16122. type, 60
  16123.   access, 65
  16124.     portability, 121
  16125.   anonymous, 62
  16126.   anonymous task, 92
  16127.   attribute, for real value, 115
  16128.   boundary value, 61
  16129.   choice affects equality, 80
  16130.   comment, 30
  16131.   conversion, 61
  16132.     precision, 115
  16133.   declaration, 35
  16134.   derived, 35, 60
  16135.   Duration, 110
  16136.     portability, 117
  16137.   enumeration, 36
  16138.   floating point, model, 114
  16139.   grouped in package, 44
  16140.   identifier, 20
  16141.   Integer, 110
  16142.   limited private, 62, 145
  16143.   name, 20, 35
  16144.   numeric, 113
  16145.   of constant, 24
  16146.   parameter passing, 85
  16147.   predefined, 35, 113
  16148.   private, 62, 145
  16149.   renaming, 36
  16150.   strong, 35, 41, 60
  16151.   subtype, 60
  16152.   suffix, 20
  16153.   unconstrained array, 131
  16154.   universal, 24
  16155.   used as range, 66
  16156.  
  16157.  
  16158.  
  16159. U
  16160.  
  16161. Unchecked_Conversion, 83
  16162.   portability, 122
  16163.  
  16164. Unchecked_Deallocation, 84
  16165.   portability, 121
  16166.  
  16167. underscore, 17
  16168.   in file name, 41
  16169.   in numbers, 17
  16170.   significant in name, 20
  16171.  
  16172. universal_integer, 24
  16173.   portability, 110
  16174.  
  16175. universal_real, 24
  16176.   for greater precision, 115
  16177.  
  16178. until loop, how to simulate, 73
  16179.  
  16180. upper case, 18
  16181.  
  16182. use clause, 78, 79
  16183.   See also context clause
  16184.  
  16185. user-defined exception, 82
  16186.   replaces implementation-defined, 119
  16187.  
  16188.  
  16189.  
  16190. V
  16191.  
  16192. variable
  16193.   declaration, alignment, 10
  16194.   localize declaration, 77
  16195.   of access type, 65
  16196.   referenced in guard, 100
  16197.   replaced with aggregate, 77
  16198.   to reduce nesting, 70
  16199.   valid state, 134
  16200.  
  16201. verb
  16202.   as entry name, 22
  16203.   as procedure name, 22
  16204.  
  16205. vertical alignment, 9, 10, 11
  16206.   See also alignment
  16207.  
  16208. virtual processor, 92
  16209.  
  16210. visibility, 46, 47, 77
  16211.   using renames clause, 79
  16212.  
  16213.  
  16214.  
  16215. W
  16216.  
  16217. while loop
  16218.   See also loop
  16219.   indentation, 7
  16220.  
  16221. with clause. See context clause
  16222.  
  16223.  
  16224.  
  16225. Z
  16226.  
  16227. zero based indexing, 154
  16228.  
  16229.